[英]JavaScript: How to group nested array
I am trying to display data using SectionList in React Native. 我试图使用React Native中的SectionList显示数据。 I have written the code below displaying what I am trying to accomplish. 我已经编写了下面的代码,显示了我想要完成的任务。
I want the data to first be grouped together by date
, and inside of that date, I need them grouped by location. 我希望数据首先按date
组合在一起,在那个日期之内,我需要按位置分组。 A regular JavaScript solution will work. 常规JavaScript解决方案将起作用。 It's important that it has a title
and data
key. 它具有title
和data
密钥非常重要。
My input data is in this format: 我的输入数据采用以下格式:
[ { game_id: 1171,
date: '2018-11-17',
location: 'Plaza'
},
{ game_id: 1189,
date: '2018-11-17',
location: 'Field - Kickball'
},
{ game_id: 1489,
date: '2018-11-16',
location: 'Field - Kickball'
},
{ game_id: 1488,
date: '2018-11-16',
location: 'Field - Soccer'
}
]
I need the obtain the following output from the data array above: 我需要从上面的数据数组中获取以下输出:
data = [{
title: "2018-11-17",
data: [{
title: "Field - Kickball",
data: [{
game_id: 1189,
date: '2018-11-17',
location: 'Field - Kickball'
}]
},
{
title: "Plaza",
data: [{
game_id: 1171,
date: '2018-11-17',
location: 'Plaza'
}]
}
]
},
{
title: "2018-11-16",
data: [{
title: "Field - Kickball",
data: [{
game_id: 1489,
date: '2018-11-16',
location: 'Field - Kickball'
}]
},
{
title: "Field - Soccer",
data: [{
game_id: 1488,
date: '2018-11-16',
location: 'Field - Soccer'
}]
}
]
}
]
I have tried this already: 我已经尝试过了:
const games = [data here]
var groups = _(games)
.groupBy(x => x.date)
.map(value => {
return _.groupBy(value, 'location')
.map(({key, value}) => ({title: key, data: value}))
})
.map((value, key) => {
return ({title: value[Object.keys(value)[0]][0].date, data: value})
})
There are a few ways this can be achieved, however a simple approach that does not require third party dependencies like Underscore or Lodash, can implemented with the built-in Array#reduce() method as shown below. 有几种方法可以实现,但是一个不需要第三方依赖的简单方法,如Underscore或Lodash,可以使用内置的Array#reduce()方法实现,如下所示。
Please see the documentation in the following code snippet for details on how this solution works: 有关此解决方案如何工作的详细信息,请参阅以下代码段中的文档:
const input = [ { game_id: 1171, date: '2018-11-17', location: 'Plaza' }, { game_id: 1189, date: '2018-11-17', location: 'Field - Kickball' }, { game_id: 1489, date: '2018-11-16', location: 'Field - Kickball' }, { game_id: 1488, date: '2018-11-16', location: 'Field - Soccer' } ]; /* Reduce input data to required nested sub-array structure */ const data = input.reduce((result, item) => { /* Construct item to be inserted into sub array for this item.date in resulting data object */ const resultItem = { title: item.location, data: [{ game_id: item.game_id, date: item.date, location: item.location }] }; /* Find existing item in result array with title that matches date */ const resultDateList = result.find(i => i.title === item.date); if (resultDateList) { /* If matching sublist found, add constructed item to it's data array */ resultDateList.data.push(resultItem); } else { /* If not matching sublist found, add a new one to the result for this item and pre-populate the data array with new item*/ result.push({ title: item.date, data: [resultItem] }); } return result; }, []) console.log(data)
Hope that helps! 希望有所帮助!
You can do something like this with ES6 and without lodash: 你可以用ES6和没有lodash做这样的事情:
let arr = [ { game_id: 1171, date: '2018-11-17', location: 'Plaza' }, { game_id: 1189, date: '2018-11-17', location: 'Field - Kickball' }, { game_id: 1489, date: '2018-11-16', location: 'Field - Kickball' }, { game_id: 1488, date: '2018-11-16', location: 'Field - Soccer' } ] let groupByfield = (data, field) => data.reduce((r, c) => { let key = c[field] r[key] = r[key] || {title: key, data: []} r[key].data = [...(r[key].data || []), c] return r }, {}) let result = Object.values(groupByfield(arr, 'date')) .map(x => ({ title: x.title, data: Object.values(groupByfield(x.data, 'location')) }) ) console.log(result)
The idea is to create your custom groupBy
function and then use it for your groupings. 我们的想法是创建自定义groupBy
函数,然后将其用于您的分组。
We are using Array.reduce , Array.map and Object.values 我们正在使用Array.reduce , Array.map和Object.values
If you want a standard solution, then you could first reduce to an object, and return the values of that object, and then group again on the output :) 如果你想要一个标准的解决方案,那么你可以先减少一个对象,然后返回该对象的值,然后再在输出上分组:)
function groupBy( arr, prop ) { return Object.values( arr.reduce( ( aggregate, item ) => { const val = item[prop]; if (!aggregate[val]) { aggregate[val] = { [prop]: val, data: [] }; } aggregate[val].data.push( item ); return aggregate; }, {} ) ); } const games = [ { game_id: 1171, date: '2018-11-17', location: 'Plaza' }, { game_id: 1189, date: '2018-11-17', location: 'Field - Kickball' }, { game_id: 1489, date: '2018-11-16', location: 'Field - Kickball' }, { game_id: 1488, date: '2018-11-16', location: 'Field - Soccer' } ]; const grouped = groupBy( games, 'date' ) .map( item => ({ ...item, data: groupBy( item.data, 'location' ) }) ); console.log( grouped );
Note that I just use the prop that got extracted as a target property for the grouping, if you want title
instead, just change the [prop]: val
to 'title': val
and then you can make your second grouping a litle bit easier :) 请注意,我只使用提取的prop作为分组的目标属性,如果你想要title
,只需将[prop]: val
更改为'title': val
然后你就可以让你的第二个分组变得更容易了:)
Generate a function using _.flow()
that can group an array by a field, and convert it to the format of { title, data }. 使用_.flow()
生成一个函数,该函数可以按字段对数组进行分组,并将其转换为{title,data}格式。 The function should also accept a transformer for the data. 该函数还应接受数据转换器。 Now you can use it recursively to group multiple times. 现在,您可以递归地使用它来多次分组。
const { identity, flow, partialRight: pr, groupBy, map } = _ const groupByKey = (key, transformer = identity) => flow( pr(groupBy, key), pr(map, (data, title) => ({ title, data: transformer(data) })) ) const data = [{"game_id":1171,"date":"2018-11-17","location":"Plaza"},{"game_id":1189,"date":"2018-11-17","location":"Field - Kickball"},{"game_id":1489,"date":"2018-11-16","location":"Field - Kickball"},{"game_id":1488,"date":"2018-11-16","location":"Field - Soccer"}] const result = groupByKey('date', groupByKey('location'))(data) console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
And the same idea with lodash/fp: 和lodash / fp一样的想法:
const { identity, flow, groupBy, map, get } = _ const groupByKey = (key, transformer = identity) => flow( groupBy(key), map(data => ({ title: get([0, key], data), data: transformer(data) })) ) const data = [{"game_id":1171,"date":"2018-11-17","location":"Plaza"},{"game_id":1189,"date":"2018-11-17","location":"Field - Kickball"},{"game_id":1489,"date":"2018-11-16","location":"Field - Kickball"},{"game_id":1488,"date":"2018-11-16","location":"Field - Soccer"}] const result = groupByKey('date', groupByKey('location'))(data) console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.