次のようなオブジェクトの配列があります。
var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}]
そして、配列内の各要素を合計して、次のような配列を生成します。
var result = [{costOfAirtickets: 4000, costOfHotel: 3200}]
マップとリデュース機能を使用しましたが、次のように個々の要素を合計することしかできませんでした:
data.map(item => ite.costOfAirtickets).reduce((prev, next)=>prev + next); // 22
現時点では、これは単一の値を生成しますが、これは最初の説明では望んでいるものではありません。
これをJavascriptまたはおそらくlodashで行う方法はありますか。
for..in
を使用してオブジェクトを反復処理し、reduce
を使用して配列を反復処理します
var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var result = [data.reduce((acc, n) => {
for (var prop in n) {
if (acc.hasOwnProperty(prop)) acc[prop] += n[prop];
else acc[prop] = n[prop];
}
return acc;
}, {})]
console.log(result)
Lodashを使用して、生活を簡素化します。
_const _ = require('lodash')
let keys = ['costOfAirtickets', 'costOfHotel'];
let results = _.zipObject(keys, keys.map(key => _.sum( _.map(data, key))))
...
{ costOfAirtickets: 4000, costOfHotel: 2200 }
_
説明:
_.sum(_.map(data, key))
:各配列の合計を生成します_.zipObject
_:結果を配列sumで圧縮します_.map
_として各キーの合計にkeys.map()
を使用すると、順序が保証されません。ドキュメンテーション:
配列をマップする必要はありません。実際には配列内の要素を減らすだけです。
const totalCostOfAirTickets: data.reduce((prev, next) => prev + next.costOfAirTickets, 0)
const totalCostOfHotel: data.reduce((prev, next) => prev + next.costOfHotel, 0)
const totals = [{totalCostOfAirTickets, totalCostOfHotel}]
一度に、次のようなことができます
const totals = data.reduce((prev, next) => {
prev.costOfAirTickets += next.costOfAirTickets;
prev.costOfHotel += next.costOfHotel;
}, {costOfAirTickets: 0, costOfHotel: 0})
別の解決策は、Map
( not Array.prototype.map)を使用することです。これには、オブジェクトと比較していくつかの 注目すべき違いがあります :
_var data = [{
costOfAirtickets: 2500,
costOfHotel: 1200
}, {
costOfAirtickets: 1500,
costOfHotel: 1000
}]
let sums = data.reduce((collection,rcd)=>{
Object.entries(rcd).forEach(([key,value])=>{
let sum = collection.get(key) || 0
collection.set(key, sum + +value)
})
return collection
}, new Map())
console.log(...sums.entries())
_
上記は最初にdata
メソッドを使用してreduce
配列を反復処理します。その中の各オブジェクトは、レコードと呼ばれます。変数rcd
を介してコード内で区別されます。
Reduceの各反復は、ループの次の反復の最初の引数として渡される値を返します。この場合、パラメーターcollection
はその引数を保持します。これは合計のセットです。
reduce
ループ内で、レコードの各キー/値ペアはforEach
を使用して繰り返されます。キー/値のペアを取得するには、_Object.entries
_メソッドを使用します。これらの引数を分解する配列を使用して、それぞれの変数key
およびvalue
に直接割り当てることができます。
プリミティブオブジェクトとは異なり、Map
には、get()
およびset()
を使用してエントリを取得および設定するための独自のメソッドがあります。したがって、最初にget()
を使用して前の合計を取得します。設定されていない場合は、デフォルトで_0
_になります。これが_|| 0
_の機能です。その時点で、以前の合計が少なくとも0以上であると想定し、現在のキーの値をその上に追加できます。
Map がやや重い場合は、 Set などの同様のオブジェクトを使用することもできます。 (get()
を除く)、またはプリミティブオブジェクト(つまり_{}
_)を使用することもできます。
lodash
アプローチです
__(data).flatMap(_.entries).groupBy(0).mapValues(v=>_.sumBy(v, 1)).value()
_
すべての一意のキーで合計されます。
_var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var res = _(data).flatMap(_.entries).groupBy(0).mapValues(v=>_.sumBy(v, 0)).value();
console.log(res);
_
_<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
_
結果として配列が必要な場合は、.castArray()
を使用してアンラップする前に、結果を_[...]
_にラップするか、最後に.value()
を使用します。
結果/削減値を作成するには、.reduce()
の代わりに.map()
メソッドを使用する必要があります。
let data = [
{costOfAirtickets: 2500, costOfHotel: 1200},
{costOfAirtickets: 1500, costOfHotel: 1000}
];
let result = data.reduce(
(a, c) => (Object.keys(c).forEach(k => (a[k] = (a[k] || 0) + c[k])), a), {}
);
console.log(result);
加算するオブジェクトを取得することで、配列を減らすことができます。
var data = [{ costOfAirtickets: 2500, costOfHotel: 1200 }, { costOfAirtickets: 1500, costOfHotel: 1000 }],
keys = ['costOfAirtickets', 'costOfHotel'],
sum = data.reduce((r, o) => {
keys.forEach(k => r[k] += o[k]);
return r;
}, Object.assign(...keys.map(k => ({ [k]: 0 }))));
console.log(sum);
私の単純な答えは次のようになります。
_var data = [{costOfAirtickets: 2500, costOfHotel: 1200},
{costOfAirtickets: 1500, costOfHotel: 1000}],
res = data.reduce((p,c) => Object.entries(c).reduce((r,[k,v]) => (r[k]+=v, r), p));
console.log(res);
_
.reduce()
の使用に関する注意:配列項目と累積値が同じタイプである場合、初期値をアキュムレーターとして使用しないことを検討し、以前の(p
)で削減することができます。および現在の(c
)要素。上記のスニペットの外部リデュースはこのタイプです。ただし、内部リデュースはオブジェクトを返すために、キー(k
)値(v
)ペアの配列を_[k,v]
_として受け取ります。したがって、初期値(p
)不可欠です。
結果は、オブジェクトとして累積された値です。配列で必要な場合は、_[res]
_のような配列に入れてください。
map
オブジェクト。合計を計算し、別のオブジェクトに保存します。
var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var result = [];
var sum = 0;
var costsum = 0;
data.map(function(item, key){
var cost = item;
//nsole.log(cost);
sum = sum + cost.costOfAirtickets;
costsum = costsum + cost.costOfHotel;
});
result = [{costOfAirtickets:sum, costOfHotel:costsum}];
console.log(result);
そのために、単純なforEach()
ループを使用できます。
var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var res = [];
var tempObj = {};
data.forEach(({costOfAirtickets, costOfHotel}) => {
tempObj['costOfAirtickets'] = (tempObj['costOfAirtickets'] || 0) + costOfAirtickets;
tempObj['costOfHotel'] = (tempObj['costOfHotel'] || 0) + costOfHotel;
});
res.Push(tempObj);
console.log(res);
以下のスニペットのように、reduceのみを使用してみてください。繰り返しを避けてください。以下のスニペットが役立つことを願っています!
var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}]
var total = data.reduce(function (result,value,key) {
result['costOfAirtickets'] = result['costOfAirtickets'] + value['costOfAirtickets'];
result['costOfHotel'] = result['costOfHotel'] + value['costOfHotel'];
return result},{costOfAirtickets:0,costOfHotel:0});
console.log(total)
これは私が考えることができる最も簡単なアプローチです
var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var sum ={};
for(var obj in data){
for(var ele in data[obj]){
if(!data[obj].hasOwnProperty(ele)) continue;
if(sum[ele] === undefined){
sum[ele] = data[obj][ele];
}else{
sum[ele] = sum[ele] + data[obj][ele];
}
}
}
var arr = [sum];
console.log(arr);
var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
var result = [data.reduce((acc, n) => {
for (var prop in n) {
if (acc[prop]) acc[prop] += n[prop];
else acc[prop] = n[prop];
}
return acc;
}, {})]
console.log(result)
ロダッシュ
lodash
reduce および _。mergeWith を使用すると、これは1つのライナーです。
var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]
var result = _.reduce(data, (r,c) => _.mergeWith(r, c, (o = 0, s) => o + s), {})
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
ES6のみ
元の配列を変異させたくない場合ES6を利用できます reduce 、 Object.entries =、および forEach このように:
var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]
// One liner
var result1 = data.reduce((r, c) =>
!Object.entries(c).forEach(([key, value]) => r[key] = (r[key] || 0) + value) && r, {})
// More readable
var result2 = data.reduce((r, c) => {
Object.entries(c).forEach(([key, value]) => r[key] = (r[key] || 0) + value)
return r
}, {})
console.log(result1)
console.log(result2)
初期のdata
配列のmutatingを気にしない場合は、1つのライナーソリューションを使用できます。
var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]
data.reduce((r, c) => !Object.entries(c).forEach(([key,value]) => r[key] += value) && r)
console.log(data[0])
より読みやすい:
var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]
data.reduce((r, c) => {
Object.entries(c).forEach(([key, value]) => r[key] += value)
return r
})
console.log(data[0])
変化する例と変化しない例の唯一の違いは、reduce
の初期値です(また、合計のアキュムレータとして0インデックスを使用します)。変化するものにはinitial value
がありませんが、他のものでは空のオブジェクトリテラルで始まります。
結果を特に配列にする必要がある場合は、変化する例の場合は[data]
を返し、純粋な例の場合は[result]
を返します。