[英]iterate over a js array of objects, within each object, check a value in the object against all others for uniqueness, push to new array
What is a good way to iterate over a js array of objects, and then within each object, check a value in the object against all others for uniqueness, and push to a new array. 遍历对象的js数组,然后在每个对象内,针对所有其他对象检查对象中的值是否唯一,然后推入新数组的一种好方法。
I have an array of objects: 我有一个对象数组:
const weatherArray = [
{
dt: 1526871600
dt_txt: "2018-05-21 03:22:00"
},
{
dt: 1526871600
dt_txt: "2018-05-22 03:30:00"
},
{
dt: 1526871600
dt_txt: "2018-05-21 03:50:00"
},
{
dt: 1526871600
dt_txt: "2018-05-23 03:17:00"
},
{
dt: 1526871600
dt_txt: "2018-05-23 03:23:00"
}
]
I need to check each object and if the dt_txt (just date, not time eg: 2018-05-23, 2018-05-21 etc) is unique, push that object into a new array. 我需要检查每个对象,如果dt_txt(只是日期,而不是时间,例如:2018-05-23、2018-05-21等)是唯一的,则将该对象推入新数组。
Below is what I have been trying, I commented to the code to show my train of thought. 下面是我一直在尝试的内容,我对代码进行了注释以显示我的思路。
var uniqueDays = []
function getDays(weatherArray) {
// push first value to new array to compare against other items
uniqueDays.push(weatherArray[0])
// get just the yyyy-mm-dd from txt we're comparing against
let firstDayString = weatherArray[0].dt_txt.split(" ")[0]
weatherArray.map((day) => {
let dayString = day.dt_txt.split(" ")[0]
uniqueDays.map((uniqueDay, index) => {
// get just the yyyy-mm-dd for new array items
let unqiueDayString = uniqueDay.dt_txt.split(" ")[0]
// if the value exists, do nothing
if (unqiueDayString == dayString) {
console.log('duplicate');
} else {
// otherwise push to new array (this is the issue)
uniqueDays.push(day)
}
})
})
return uniqueDays
}
The issue I am having is that pushing to unique day's within it's own map function is causing a recursion issue. 我遇到的问题是,在自己的地图函数中推入唯一的日期会导致递归问题。 I know there has to be a better way to this.
我知道必须有一个更好的方法。 Any help or direction would be a big relief, I've been struggling with this for some time.
任何帮助或指示都将是一个很大的缓解,我已经为此苦苦挣扎了一段时间。
You can group objects in an array with .reduce
, putting each unique date into an object indexed by date and then getting that object's values: 您可以使用
.reduce
将数组中的对象分组,将每个唯一日期放入按日期索引的对象中,然后获取该对象的值:
const weatherArray=[{dt:1526871600,dt_txt:"2018-05-21 03:22:00"},{dt:1526871600,dt_txt:"2018-05-22 03:30:00"},{dt:1526871600,dt_txt:"2018-05-21 03:50:00"},{dt:1526871600,dt_txt:"2018-05-23 03:17:00"},{dt:1526871600,dt_txt:"2018-05-23 03:23:00"}]; const output = Object.values( weatherArray.reduce((accum, obj) => { const date = obj.dt_txt.slice(0, 10); if (!accum[date]) accum[date] = obj; return accum; }, {}) ); console.log(output);
const weatherArray = [ { dt: 1526871600, dt_txt: "2018-05-21 03:22:00" }, { dt: 1526871600, dt_txt: "2018-05-22 03:30:00" }, { dt: 1526871600, dt_txt: "2018-05-21 03:50:00" }, { dt: 1526871600, dt_txt: "2018-05-23 03:17:00" }, { dt: 1526871600, dt_txt: "2018-05-23 03:23:00" } ] const seen = {}; const res = weatherArray.filter(function(dt){ const date = dt.dt_txt.substring(0, 10); if (!seen[date]) { seen[date] = true; return true; } }); console.log(res);
note that it's not clear how robust you need to parse your dates. 请注意,尚不清楚您需要解析日期的鲁棒性。 Looking at your example all dates are in the format YYYY-MM-DD so I just used
substring
which would be faster than split
or a regular expression. 在您的示例中,所有日期均为YYYY-MM-DD格式,因此我只使用了比
split
或正则表达式快的substring
。
As for why your code doesn't work it's because you're looping over uniqueDays
but also pushing to it inside the loop . 至于为什么代码不起作用,是因为您要遍历
uniqueDays
但还要在循环内推送它。 That's a no-no. 那是不可以的。
The code you posted is parsing the dates in uniqueDays
every time. 您发布的代码每次都会解析
uniqueDays
的日期。 For a large collection that would be slow. 对于大型集合,这将很慢。 The solution above only needs to parse the dates once per item so that would be faster.
上面的解决方案只需要为每个项目解析一次日期,这样会更快。
Your code uses map
but map
generates a new array from whatever the function passed to map returns. 您的代码使用
map
但是map
根据传递给map的函数返回的值生成一个新数组。 In your case it's generating an array of undefined as in [undefined, undefined, undefined]
and then throwing that array away. 在您的情况下,它会生成一个
[undefined, undefined, undefined]
数组,然后将其扔掉。 You probably wanted to use forEach
. 您可能想使用
forEach
。
I'm assuming you looped because you needed to keep parsing the dates. 我假设您循环播放是因为您需要继续解析日期。 If you didn't parse the dates you can use
someArray.indexOf
to find if there is an entry in an array as in 如果您不解析日期,则可以使用
someArray.indexOf
来查找数组中是否有条目,如
const isInArray = someArray.indexOf(value) >= 0;
You can also use someArray.findIndex
which takes a function so you could have used that to parse the dates. 您还可以使用
someArray.findIndex
函数的someArray.findIndex
,以便可以使用它来解析日期。
But, finally, looking through an array is slow, checking if a property exists in an object is fast. 但是,最后,遍历数组的速度很慢,检查对象中是否存在属性的速度很快。 Because of the differences between arrays and objects the algorithm for finding a property, a hashmap, is
O(1)
where as to find an value in an unsorted array is O(N/2)
. 由于数组和对象之间的差异,用于查找属性的算法
O(1)
哈希图)为O(1)
,而在未排序的数组中查找值的算法为O(N/2)
。
Let me add that @CertainPerformance's solution is also elegant. 让我补充一点,@ CertainPerformance的解决方案也很优雅。 It's collecting the objects in
accum
and then has to iterate over that object to generate an array when it calls Object.values
. 它的收集中的对象
accum
,然后必须遍历该对象时,它调用以产生阵列Object.values
。 For a large result array that would theoretically be slower than not having that second hidden loop. 对于较大的结果数组,理论上比没有第二个隐藏循环要慢。
const newUniqWeatherArray = [];
weatherArray.forEach(x => {
const date = x.dt_txt.split(' ')[0];
if(!newUniqWeatherArray.some((x) => x.dt_txt.split(' ')[0] === date)){
newUniqWeatherArray.push(x);
}
})
Basically the pseudocode is as below: 伪代码基本上如下:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.