2017-07-31 96 views
-1

我想在JavaScript中做一些映射。我想要做的是我試圖檢查arr中的類型是否存在於datasetarr中,如果存在,我得到datasetarr中的索引並增加該索引的數量。如果不存在,我在datasetarr中添加一個新條目。這裏是我的代碼:JavaScript排序和分組中的項目

var datasetarr = []; 
var pos; 
for(var i = 0; i < arr.length; i++){ 
    console.log('unsorted ' + arr[i].type + ' ' + arr[i].quantity); 
    if(datasetarr.indexOf(arr[i].type) > -1){ 
     pos = datasetarr.indexOf(arr[i].type); 
     datasetarr[pos].quantity += arr[i].quantity; 
    }else{ 
     datasetarr.push({type: arr[i].type, quantity: arr[i].quantity}); 
    } 
} 

for(var i = 0; i < datasetarr.length; i++){ 
    console.log('sorted ' + datasetarr[i].type + ' ' + datasetarr[i].quantity); 
} 

輸出應該是:

kitchen appliance 20 
home entertainment 8 
batteries & lightings 4 
home appliance 12 

然後,我可以得到的種類和數量每存入數組我與圖表繪製。

但是,用我上面的代碼,我得到的東西和未排序的完全一樣。任何想法,我的邏輯哪部分出錯?

+0

它會更容易幫助你,如果你與實際陣列替換圖像(代碼).. – MedAli

+0

如果你可以添加一些有用的代碼,比如「數組A」,「數組B」和「datasetarr」會更容易。或者甚至更好,在小提琴,片段或類似的工作示例。 – gmo

+0

編輯的問題與ARR和適當的命名約定,而不是陣列A/B – guest176969

回答

3

使用對象進行分組。

var categories = {}; 

function incrementBy(category, value) { 
    if (!categories[category]) { 
    categories[category] = 0; 
    } 
    categories[category] += value; 
} 

var datasetarr = []; 
var pos; 
for(var i = 0; i < arr.length; i++){ 
    console.log('unsorted ' + arr[i].type + ' ' + arr[i].quantity); 
    incrementBy(arr[i].type, arr[i].quantity) 
} 

for(var category in categories){ 
    console.log('sorted ' + category + ' ' + categories[category]); 
} 

如果需要,可以將對象分解成數組並根據需要進行排序。

一點點清潔的例子,這可能讓你沿着一個小咬更好地遵循:

function group(array) { 
    var categories = {}; 

    function incrementBy(object) { 
     var category = categories[object.type]; 
     if (!category) { 
      category = categories[object.type] = {}; 
     } 
     var subCategory = category[object.subType]; 
     if (!subCategory) { 
      subCategory = category[object.subType] = {}; 
     } 
     subCategory += object.value; 
    } 

    array.forEach(function (value, index, arr) { 
     incrementBy(value, value.quantity) 
    }); 

    return categories; 
} 

var arr = [{type: 'kitchen appliance', quantity: 2}, 
    {type: 'home entertainment', quantity: 2}, 
    {type: 'home entertainment', quantity: 3}, 
    {type: 'batteries & lightings', quantity: 2}, 
    {type: 'home entertainment', quantity: 2}, 
    {type: 'home appliance', quantity: 5}, 
    {type: 'kitchen appliance', quantity: 4}, 
    {type: 'kitchen appliance', quantity: 5}, 
    {type: 'kitchen appliance', quantity: 3}, 
    {type: 'kitchen appliance', quantity: 4}, 
    {type: 'kitchen appliance', quantity: 1}, 
    {type: 'home entertainment', quantity: 1}, 
    {type: 'home appliance', quantity: 5}, 
    {type: 'batteries & lightings', quantity: 2}, 
    {type: 'kitchen appliance', quantity: 2}, 
    {type: 'home appliance', quantity: 2}]; 


function group(array) { 
    var categories = {}; 

    function incrementBy(category, value) { 
     if (!categories[category]) { 
      categories[category] = 0; 
     } 
     categories[category] += value; 
    } 

    array.forEach(function (value, index, arr) { 
     incrementBy(value.type, value.quantity) 
    }); 

    return categories; 
} 

function print(categories) { 
    for (var category in categories) { 
     console.log('%s: %s', category, categories[category]); 
    } 
} 

print(group(arr)); 

這裏的group隱藏分組,這比可容納自己的實現的解決方案

根據你的使用情況,您也可以扁平化結構:

function incrementBy(object) { 
    var key = [object.type, object.subType].join('/'); 
    var category = categories[key]; 
    if (!category) { 
     category = categories[key] = {}; 
    } 
    subCategory += object.value; 
} 

但它可能是有意義的有各種地圖到位:

function groupings(array) { 
    var groupings = { 
     types: {}, 
     subTypes: {}, 
     paths: {} 
    }; 

    function incrementBy(object) { 
     var category = groupings['types'][object.type]; 
     if (!category) { 
      category = groupings['types'][object.type] = {}; 
     } 
     category += object.value; 

     var subCategory = groupings['subTypes'][object.subType]; 
     if (!subCategory) { 
      subCategory = groupings['subTypes'][object.subType] = {}; 
     } 
     subCategory += object.value; 


     var key = [object.type, object.subType].join('/'); 
     var path = groupings['paths'][key]; 
     if (!path) { 
      path = groupings['paths'][key] = {}; 
     } 
     path += object.value; 
    } 

    array.forEach(function (value, index, arr) { 
     incrementBy(value, value.quantity) 
    }); 

    return categories; 
} 

爲了避免聚合信息丟失,你可以簡單地創建一個更復雜的數據結構:

function groupByAndSumBy(data, groupByProperty, sumByProperty) { 
    var accumulator = {}; 

    data.forEach(function(object, index, array) { 
     var localAcc = accumulator[groupByProperty] 
      = accumulator[groupByProperty] || { items: [] }; 
     localAcc[sumByProperty] 
      = (localAcc[sumByProperty] || 0) + object[sumByProperty]; 
     localAcc.items.push(object); 
    }); 

    return accumulator; 
} 

function groupByMerchantNameAndSumByTotalSales(data) { 
    return groupByAndSumBy(data, 'merchantName', 'totalSales'); 
} 

這將創建一個集合,其還包含輸入數組的子集,它允許您更詳細地查看數據。

+0

你在哪裏申報類別?裏面的incrementBy函數和for循環函數都在那裏? – guest176969

+0

'category'基本上是'arr [i] .type'。所以它只是定義了什麼方法被調用。 –

+0

對不起,但我的意思是上面的代碼是兩個單獨的功能吧?兩個for循環在一個函數中,而incrementBy作爲另一個函數。他們都使用類別對象,所以我在這兩個函數中聲明瞭對象。但不知何故,它現在不打印任何東西。 – guest176969

0

那是因爲,你如果條件只檢查所得到的陣列datasetarr這已經是空的要推下一值索引值,

所以你

 if(datasetarr.indexOf(arr[i].type) > -1){ 
     pos = datasetarr.indexOf(arr[i].type); 
     datasetarr[pos].quantity += arr[i].quantity; 
    } 

永遠執行。 這就是你得到與輸入相同的輸出的原因。

+0

嗯所以我該如何解決它? – guest176969

+0

而不是**如果**循環調用一個函數來只將** distinct **類別推送到結果數組** ** datasetarr **,並繼續在函數的每個調用中添加相同的數量。 或者你想我爲你寫邏輯? –

0

您可以編寫一個這樣的通用聚集函數,並通過指定分類和聚合的鍵來分別調用typequantity。最後,您指定reducer功能,這只是一個總金額,a + b

function aggregate (array, predicate, value, reducer) { 
 
    // group values by predicate 
 
    var groups = array.reduce(function (groups, item) { 
 
    if (item[predicate] in groups) { 
 
     groups[item[predicate]].push(item[value]) 
 
    } else { 
 
     groups[item[predicate]] = [item[value]] 
 
    } 
 

 
    return groups 
 
    }, {}) 
 

 
    // aggregate each group of values by reducer 
 
    return Object.keys(groups).map(function (group) { 
 
    var summary = {} 
 
    summary[predicate] = group 
 
    summary[value] = groups[group].reduce(reducer, 0) 
 
    return summary 
 
    }) 
 
} 
 

 
// input array 
 
var arr = [{ type: 'kitchen appliance', quantity: 2 }, { type: 'home entertainment', quantity: 2 }, { type: 'home entertainment', quantity: 3 }, { type: 'batteries & lightings', quantity: 2 }, { type: 'home entertainment', quantity: 2 }, { type: 'home appliance', quantity: 5 }, { type: 'kitchen appliance', quantity: 4 }, { type: 'kitchen appliance', quantity: 5 }, { type: 'kitchen appliance', quantity: 3 }, { type: 'kitchen appliance', quantity: 4 }, { type: 'kitchen appliance', quantity: 1 }, { type: 'home entertainment', quantity: 1 }, { type: 'home appliance', quantity: 5 }, { type: 'batteries & lightings', quantity: 2 }, { type: 'kitchen appliance', quantity: 2 }, { type: 'home appliance', quantity: 2 }] 
 

 
// output array 
 
var sums = aggregate(arr, 'type', 'quantity', function (a, b) { return a + b }) 
 

 
// formatting 
 
var output = sums.map(function (item) { 
 
    return item.type + ' ' + item.quantity 
 
}) 
 

 
// string output 
 
console.log(output.join('\n'))

+0

我明白了,但有什麼辦法從輸出中獲取類型和數量?像例如output.type或output.quantity?因爲我會用它們來繪製圖表。到目前爲止,輸出結果形成一個字符串right – guest176969

+1

我剛纔向你展示了它是如何的,它在最後兩條語句中......並且你確實聲明這是你想要的輸出格式,所以如果這不是你想要的,你應該有說首先你需要什麼。 –

+0

正如我想從輸出中獲取所有類型並將其存儲到臨時數組中,並將所有數量從輸出存儲到另一個臨時數組中。然後,我將使用這兩個臨時數組來繪製圖表。目前輸出本身是一個字符串形式,因此output.type,output.quantity返回undefined – guest176969

2

一般情況下,我建議lodash對這種東西

result = _(arr) 
    .groupBy('type') 
    .mapValues(xs => _.sumBy(xs, 'quantity')) 
    .value(); 

然而,在這種特殊情況下,香草JS解決方案同樣簡單:

let result = {}; 

for (let item of arr) 
    result[item.type] = (result[item.type] || 0) + item.quantity; 
+0

這個問題沒有標記[tag:lodash]或[tag:ecmascript-6],但是如果你打算使用ES6,你可能還會爲'(let {type,quantity} of arr)' –

+0

@PatrickRoberts :截至2017年,我認爲默認情況下假設ES6用於'javascript'問題是安全的。 – georg

+0

我不同意。如果提問者使用ES5(除了不使用ES6功能外,'var'是一個很大的提示),普遍的共識是用ES5回答。無論如何,我都喜歡你的答案,因爲我認爲使用lodash很方便,但我主要給你提供建議以改善你的ES6答案。 –

-1

基於OP問題:

我試着檢查從ARR的類型datasetarr存在,如果存在,我得到datasetarr索引並增加該索引的數量。如果不存在,我在datasetarr中添加一個新條目。

而且澄清意見:

問:所以基本上你要組陣列ARR的類型和數量總和值? (並輸出結果在數據定位器)
答:是的,這是我想要實現的。

我認爲最簡單的方法就是做到這一點,檢查是否存在並採取相應措施。

var datasetarr = []; 
for (var i = arr.length - 1; i >= 0; i--) { 
    if (datasetarr.hasOwnProperty(arr[i]["type"])) { 
    // exist -> increment 
    datasetarr[arr[i]["type"]] = datasetarr[arr[i]["type"]] + arr[i]["quantity"]; 
    } else { 
    // no exist -> add new 
    datasetarr[arr[i]["type"]] = arr[i]["quantity"]; 
    } 
} 

datasetarr可變預計產出將是:

datasetarr = { 
    "batteries & lightings" => 4, 
    "home appliance" => 12, 
    "home entertainment" => 8, 
    "kitchen appliance" => 21 
];