2016-09-23 7 views
1

Typescriptでオブジェクトの配列からカスタムオブジェクトを構築する必要があります。オブジェクトの配列を反復処理してカスタムオブジェクトを出力する

以下の例では、salesman_1_nameが配列に含まれる回数をカウントし、各Salesman_1_nameのグロスを追加し、salesman_1_nameごとに保証がnullでない場合にカウントする方法を教えてください。私が持っているのであれば:

[ 
    {salesman_1_name:Brian, gross:100, warranty: Easycare}, 
    {salesman_1_name:Brian, gross:100, warranty: Easycare}, 
    {salesman_1_name:Brian, gross:100, warranty: null}, 
    {salesman_1_name:Kreso, gross:100, warranty: null}, 
    {salesman_1_name:Filip, gross:100, warranty: Easycare} 
] 

を私は出力する必要があるでしょう:

[ 
    Name:Brian, Count:3, Gross:300, WarrantyCount:2, 
    Name:Kreso, Count:1, Gross:100, WarrantyCount:0, 
    Name:Filip, Count:1, Gross:100, WarrantyCount:1 
] 
+0

は 'Easycare'文字列ですか? WarrantyCountはどこから手に入りますか? –

+0

はい、私はこの例の2つの「Brian」行に保証名を追加するつもりでした。私は保証がヌルでない場合にカウントする必要があります+ + – BHead

+1

なぜ 'Filip ... WarrantyCount:1'と' Brian ... WarrantyCount:2'? –

答えて

1

あなたは名前のグループへの参照としてオブジェクトを使用して、凝集を作ることができます。

var data = [{ salesman_1_name: 'Brian', gross: 100, warranty: 'Easycare' }, { salesman_1_name: 'Brian', gross: 100, warranty: 'Easycare' }, { salesman_1_name: 'Brian', gross: 100, warranty: null }, { salesman_1_name: 'Kreso', gross: 100, warranty: null }, { salesman_1_name: 'Filip', gross: 100, warranty: 'Easycare' }], 
 
    grouped = []; 
 

 
data.forEach(function (a) { 
 
    if (!this[a.salesman_1_name]) { 
 
     this[a.salesman_1_name] = { Name: a.salesman_1_name, Count: 0, Gross: 0, WarrantyCount: 0 }; 
 
     grouped.push(this[a.salesman_1_name]); 
 
    } 
 
    this[a.salesman_1_name].Count++; 
 
    this[a.salesman_1_name].Gross += a.gross; 
 
    a.warranty !== null && this[a.salesman_1_name].WarrantyCount++;  
 
}, Object.create(null)); 
 

 
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

+0

1/2:私はあなたのアプローチが大好きですが、今回は私はニックピッキングします。 'reduce'が望ましいアプローチであるべきです。それには2つの議論があります。このアプローチでは、マップオブジェクトやアキュムレータオブジェクトとして、通常のオブジェクトリテラル{{} 'の代わりに' Object.create(null) 'を使う理由と追加のターゲットオブジェクトを使用します。多くの人にとって、2番目の視線でもあまり明確ではありません)... –

+0

2/2:...一方、コードは最終的なアキュムレータオブジェクトとして 'grouped '外部オブジェクトに固執する必要があります。 'reduce'を使うと、すべてが無料で取得され、コールバックのコードはよりエレガントで、はるかに再利用可能になります。 –

+0

'toString'のようなハッシュを持っていると、存在のチェックが間違った結果につながります。私はforEachを使用しています。これはreduceの性質のため、この例では常に同じですが、実際には変更されていない結果セットへの参照が、合計または単一のプリミティブ/変更オブジェクトとして存在します。 –

1
data.reduce((acc, cur) => { 
    const obj = acc.find(x => x.Name === cur.salesman_1_name); 
    if (obj) { 
    obj.Gross += cur.gross; 
    obj.WarrantyCount = cur.warranty !== null ? obj.WarrantyCount + 1 : obj.WarrantyCount; 
    } else { 
    acc.push({ Name: cur.salesman_1_name, Gross: cur.gross, WarrantyCount: cur.warranty !== null ? 1 : 0 }); 
    } 
    return acc; 
}, []); 
+0

の各反復ステップでは、実際には「減らす」必要はなく、また、蓄積リスト内の関連するセールスマンアイテムを検索する必要もありません。 –

0

// Code goes here 
 

 
var data = [{ 
 
    salesman_1_name: 'Brian', 
 
    gross: 100, 
 
    warranty: 'Easycare' 
 
}, { 
 
    salesman_1_name: 'Brian', 
 
    gross: 100, 
 
    warranty: 'Easycare' 
 
}, { 
 
    salesman_1_name: 'Brian', 
 
    gross: 100, 
 
    warranty: null 
 
}, { 
 
    salesman_1_name: 'Kreso', 
 
    gross: 100, 
 
    warranty: null 
 
}, { 
 
    salesman_1_name: 'Filip', 
 
    gross: 100, 
 
    warranty: 'Easycare' 
 
}]; 
 

 

 
var result = (function(myArray) { 
 
    var obj = []; //also can be used Object.values(dataCollector) 
 
    var dataCollector = myArray.reduce(function(dataCollector, currentItem) { 
 

 
    if (!dataCollector[currentItem['salesman_1_name']]) { 
 
     dataCollector[currentItem['salesman_1_name']] = { 
 
     Name: currentItem.salesman_1_name, 
 
     Count: 0, 
 
     Gross: currentItem.gross, 
 
     WarrantyCount: currentItem['salesman_1_name'].warranty != null ? 0 : 1 
 
     }; 
 

 
    } else { 
 
     dataCollector[currentItem['salesman_1_name']].Count++; 
 
     dataCollector[currentItem['salesman_1_name']].Gross += currentItem.gross; 
 
     if (currentItem['salesman_1_name'].warranty !== null) { 
 
     dataCollector[currentItem['salesman_1_name']].WarrantyCount++; 
 
     } 
 

 
    } 
 

 
    return dataCollector; 
 

 
    }, {}); 
 

 
    for (var key in dataCollector) { 
 
    if (dataCollector.hasOwnProperty(key)) { 
 
     obj.push(dataCollector[key]); 
 
    } 
 
    } 
 
    return obj; 
 

 
})(data) 
 

 
console.log(result);

+0

@ Vladulonut ... uhh ... 2つの出口点 - 'return obj'と' return dataCollector' - 早期終了の最終条件とともに、 'reduce'の各反復で処理する必要があります。' reduce 'とそのアキュムレータオブジェクトは本当にもっとエレガントに使うことができます...最後の条件でも、' reduce'のコールバック関数の4番目の引数として与えられるので、外部リストを参照する必要はありません。このコールバックの内側から縮小リストを参照し、まだ名前で知られていない配列を処理することができます。 –

+0

レビューのための@PeterSeliger thx、私はいくつかの変更を加えました –

0

var rawSalesmanData = [ 
 
    { salesman_1_name: "Brian", gross: 100, warranty: "Easycare" }, 
 
    { salesman_1_name: "Brian", gross: 100, warranty: "Easycare" }, 
 
    { salesman_1_name: "Brian", gross: 100, warranty: null }, 
 
    { salesman_1_name: "Kreso", gross: 100, warranty: null }, 
 
    { salesman_1_name: "Filip", gross: 100, warranty: "Easycare" } 
 
]; 
 

 
var salesmanSpecificList = rawSalesmanData.reduce(function (collector, rawDataItem/*, idx, rawDataList*/) { 
 

 
    var map  = collector.map; 
 
    var key  = rawDataItem.salesman_1_name; 
 
    var namedItem = map[key]; 
 

 
    if (!namedItem) { 
 
     namedItem = map[key] = { 
 
      name   : key, 
 
      occurencyCount : 0, 
 
      grossTotal  : 0, 
 
      warrantyCount : 0 
 
     }; 
 
     collector.list.push(namedItem); 
 
    } 
 
    namedItem.occurencyCount++; 
 
    namedItem.grossTotal = (namedItem.grossTotal + rawDataItem.gross); 
 
    namedItem.warrantyCount = (namedItem.warrantyCount + ((rawDataItem.warranty !== null) ? 1 : 0)); 
 

 
    return collector; 
 

 
}, { 
 

 
    map : {}, 
 
    list: [] 
 

 
}).list; 
 

 

 
console.log("salesmanSpecificList : ", salesmanSpecificList);

関連する問題