オブジェクトがあります。以下のようになります:
[
{
"name":"Display",
"group":"Technical detals",
"id":"60",
"value":"4"
},
{
"name":"Manufacturer",
"group":"Manufacturer",
"id":"58",
"value":"Apple"
},
{
"name":"OS",
"group":"Technical detals",
"id":"37",
"value":"Apple iOS"
}
]
このデータをグループフィールドでグループ化して、このオブジェクトを取得します。
var obj = {
0 = [
{
'group' = 'Technical detals',
'name' = 'Display',
'id' = '60',
'value' = '4'
},
{
'group' = 'Technical detals',
'name' = 'OS',
'id' = '37',
'value' = 'Apple iOS'
}],
1 = [
{
'group' = 'Manufacturer',
'name' = 'Manufacturer',
'id' = '58',
'value' = 'Apple'
}]
}
最初のオブジェクトをどのようにグループ化できますか?
次のようなもので試してください:
function groupBy(collection, property) {
var i = 0, val, index,
values = [], result = [];
for (; i < collection.length; i++) {
val = collection[i][property];
index = values.indexOf(val);
if (index > -1)
result[index].Push(collection[i]);
else {
values.Push(val);
result.Push([collection[i]]);
}
}
return result;
}
var obj = groupBy(list, "group");
それを念頭に置いて Array.prototype.indexOf
はIE8以前では定義されていませんが、一般的なポリフィルがあります。
アプリケーションでunderscore.jsを使用している場合は、次の操作を行うだけです。
var groups = _.groupBy(data, 'group'); // data is your initial collection
または、ライブラリを使用したくない場合は、自分で実行できます。
var groups = { };
data.forEach(function(item){
var list = groups[item.group];
if(list){
list.Push(item);
} else{
groups[item.group] = [item];
}
});
両方の例を実際に見ることができます http://jsfiddle.net/nkVu6/3/
ES6 Map
を使用したい場合は、次のようにします。
function groupBy(arr, prop) {
const map = new Map(Array.from(arr, obj => [obj[prop], []]));
arr.forEach(obj => map.get(obj[prop]).Push(obj));
return Array.from(map.values());
}
const data = [{ name: "Display", group: "Technical detals", id: 60, value: 4 }, { name: "Manufacturer", group: "Manufacturer", id: 58, value: "Apple" }, { name: "OS", group: "Technical detals", id: 37, value: "Apple iOS" }];
console.log(groupBy(data, "group"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Map
インスタンスは、入力配列から生成されたキーと値のペアから作成されます。キーはグループ化するプロパティの値であり、値は空の配列として初期化されます。
次に、それらのアレイにデータが入力されます。最後に、マップの値(つまり、入力された配列)が返されます。
Reduce は、このような状況に最適です。以下のlist
が入力データです。
const list = [{
'name': 'Display',
'group': 'Technical detals',
'id': '60',
'value': '4'
},
{
'name': 'Manufacturer',
'group': 'Manufacturer',
'id': '58',
'value': 'Apple'
},
{
'name': 'OS',
'group': 'Technical detals',
'id': '37',
'value': 'Apple iOS'
}
];
const groups = list.reduce((groups, item) => {
const group = (groups[item.group] || []);
group.Push(item);
groups[item.group] = group;
return groups;
}, {});
console.log(groups);
そして、不変になりたい場合は、次のようにreduce
を書くことができます。
const list = [{
'name': 'Display',
'group': 'Technical detals',
'id': '60',
'value': '4'
},
{
'name': 'Manufacturer',
'group': 'Manufacturer',
'id': '58',
'value': 'Apple'
},
{
'name': 'OS',
'group': 'Technical detals',
'id': '37',
'value': 'Apple iOS'
}
];
const groups = list.reduce((groups, item) => ({
...groups,
[item.group]: [...(groups[item.group] || []), item]
}), {});
console.log(groups);
環境でスプレッド構文が許可されているかどうかによって異なります。
グループと Array#forEach
配列を繰り返すため。
次に、ハッシュが存在するかどうかを確認し、存在しない場合は空の配列を割り当てて、結果セットにプッシュします。
後で実際の要素をハッシュの配列にプッシュします。
function groupBy(array, group) {
var hash = Object.create(null),
result = [];
array.forEach(function (a) {
if (!hash[a[group]]) {
hash[a[group]] = [];
result.Push(hash[a[group]]);
}
hash[a[group]].Push(a);
});
return result;
}
var data = [{ name: "Display", group: "Technical detals", id: 60, value: 4 }, { name: "Manufacturer", group: "Manufacturer", id: 58, value: "Apple" }, { name: "OS", group: "Technical detals", id: 37, value: "Apple iOS" }];
console.log(groupBy(data, "group"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
最初の配列がdata
に割り当てられているとしましょう
data.reduce((acc, d) => {
if (Object.keys(acc).includes(d.group)) return acc;
acc[d.group] = data.filter(g => g.group === d.group);
return acc;
}, {})
これはあなたに何かを与えるでしょう
{
"Technical detals" = [
{
'group' = 'Technical detals',
'name' = 'Display',
'id' = '60',
'value' = '4'
},
{
'group' = 'Technical detals',
'name' = 'OS',
'id' = '37',
'value' = 'Apple iOS'
}],
"Manufacturer" = [
{
'group' = 'Manufacturer',
'name' = 'Manufacturer',
'id' = '58',
'value' = 'Apple'
}]
}
承認済みとマークされた回答を使用しようとしましたが、評価されているプロパティのタイプによっては、一部のグループで欠落している要素があることに気付きました。これはその答えから導き出された解決策です:
function groupBy(collection, property) {
var i = 0, values = [], result = [];
for (i; i < collection.length; i++) {
if(values.indexOf(collection[i][property]) === -1) {
values.Push(collection[i][property]);
result.Push(collection.filter(function(v) { return v[property] === collection[i][property] }));
}
}
return result;
}
var obj = groupBy(list, "group");
試す
let g = (d,h={},r={},i=0)=>(d.map(x=>(y=x.group,h[y]?1:(h[y]=++i,r[h[y]-1]=[]),r[h[y]-1].Push(x))),r);
console.log( g(data) );
let data=[
{
"name":"Display",
"group":"Technical detals",
"id":"60",
"value":"4"
},
{
"name":"Manufacturer",
"group":"Manufacturer",
"id":"58",
"value":"Apple"
},
{
"name":"OS",
"group":"Technical detals",
"id":"37",
"value":"Apple iOS"
}
];
let g = (d,h={},r={},i=0)=>(d.map(x=>(y=x.group,h[y]?1:(h[y]=++i,r[h[y]-1]=[]),r[h[y]-1].Push(x))),r);
console.log(g(data));
Lodashを使用している場合は、 groupBy
を使用できます。
配列とオブジェクトの両方をサポートしています。
例:
_.groupBy([6.1, 4.2, 6.3], Math.floor);
// => { '4': [4.2], '6': [6.1, 6.3] }
// The `_.property` iteratee shorthand.
_.groupBy(['one', 'two', 'three'], 'length');
// => { '3': ['one', 'two'], '5': ['three'] }