[英]How to get distinct values from an array of objects in JavaScript?
假设我有以下内容:
var array =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
能够获得所有不同年龄的数组的最佳方法是什么,以便我得到以下结果数组:
[17, 35]
有什么方法可以替代地构建数据或更好的方法,这样我就不必遍历每个数组来检查“age”的值并检查另一个数组是否存在,如果不存在则添加它?
如果有某种方法我可以在不重复的情况下提取不同的年龄......
当前低效的方式我想改进......如果这意味着不是“数组”是一个对象数组,而是一个具有一些唯一键(即“1,2,3”)的对象的“映射”,那将是也可以。 我只是在寻找最高效的方式。
以下是我目前的做法,但对我来说,迭代似乎只是效率低下,即使它确实有效......
var distinct = []
for (var i = 0; i < array.length; i++)
if (array[i].age not in distinct)
distinct.push(array[i].age)
如果您使用的是 ES6/ES2015 或更高版本,您可以这样做:
const data = [
{ group: 'A', name: 'SD' },
{ group: 'B', name: 'FI' },
{ group: 'A', name: 'MM' },
{ group: 'B', name: 'CO'}
];
const unique = [...new Set(data.map(item => item.group))]; // [ 'A', 'B']
这是有关如何执行此操作的示例。
对于那些想要返回具有键唯一属性的对象的人
const array = [ { "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 } ] const key = 'age'; const arrayUniqueByKey = [...new Map(array.map(item => [item[key], item])).values()]; console.log(arrayUniqueByKey); /*OUTPUT [ { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 } ] */ // Note: this will pick the last duplicated item in the list.
使用 ES6
let array = [
{ "name": "Joe", "age": 17 },
{ "name": "Bob", "age": 17 },
{ "name": "Carl", "age": 35 }
];
array.map(item => item.age)
.filter((value, index, self) => self.indexOf(value) === index)
> [17, 35]
使用 ES6 功能,您可以执行以下操作:
const uniqueAges = [...new Set( array.map(obj => obj.age)) ];
如果这是 PHP,我会用键构建一个数组并在最后使用array_keys
,但是 JS 没有这样的奢侈。 相反,试试这个:
var flags = [], output = [], l = array.length, i;
for( i=0; i<l; i++) {
if( flags[array[i].age]) continue;
flags[array[i].age] = true;
output.push(array[i].age);
}
您可以使用像这样的字典方法。 基本上,您将想要区分的值分配为“字典”中的键(这里我们使用数组作为对象以避免字典模式)。 如果该键不存在,则将该值添加为不同的。
这是一个工作演示:
var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}]; var unique = []; var distinct = []; for( let i = 0; i < array.length; i++ ){ if( !unique[array[i].age]){ distinct.push(array[i].age); unique[array[i].age] = 1; } } var d = document.getElementById("d"); d.innerHTML = "" + distinct;
<div id="d"></div>
这将是 O(n),其中 n 是数组中对象的数量,m 是唯一值的数量。 没有比 O(n) 更快的方法了,因为您必须至少检查每个值一次。
之前的版本使用了一个对象和 for in。这些在本质上是次要的,并且已经在上面进行了次要更新。 但是,原始 jsperf 中两个版本之间的性能似乎有所提高的原因是数据样本量非常小。 因此,之前版本的主要比较是查看内部映射和过滤器使用与字典模式查找之间的差异。
如前所述,我已经更新了上面的代码,但是,我还更新了 jsperf 以查看 1000 个对象而不是 3 个。3 忽略了许多涉及的性能缺陷(过时的 jsperf )。
表现
https://jsperf.com/filter-vs-dictionary-more-data当我运行这本词典时,速度提高了 96%。
从 2017 年 8 月 25 日起,您将通过 ES6 for Typescript 使用新的 Set 来解决此问题
Array.from(new Set(yourArray.map((item: any) => item.id)))
我只是映射和删除重复:
var ages = array.map(function(obj) { return obj.age; });
ages = ages.filter(function(v,i) { return ages.indexOf(v) == i; });
console.log(ages); //=> [17, 35]
编辑:好吧! 就性能而言,这不是最有效的方法,而是最简单最易读的 IMO。 如果您真的关心微优化或者您拥有大量数据,那么常规for
循环将更加“高效”。
var unique = array
.map(p => p.age)
.filter((age, index, arr) => arr.indexOf(age) == index)
.sort(); // sorting is optional
// or in ES6
var unique = [...new Set(array.map(p => p.age))];
// or with lodash
var unique = _.uniq(_.map(array, 'age'));
ES6 示例
const data = [
{ name: "Joe", age: 17},
{ name: "Bob", age: 17},
{ name: "Carl", age: 35}
];
const arr = data.map(p => p.age); // [17, 17, 35]
const s = new Set(arr); // {17, 35} a set removes duplications, but it's still a set
const unique = [...s]; // [17, 35] Use the spread operator to transform a set into an Array
// or use Array.from to transform a set into an array
const unique2 = Array.from(s); // [17, 35]
已经有很多有效的答案,但我想添加一个只使用reduce()
方法的答案,因为它干净简单。
function uniqueBy(arr, prop){
return arr.reduce((a, d) => {
if (!a.includes(d[prop])) { a.push(d[prop]); }
return a;
}, []);
}
像这样使用它:
var array = [
{"name": "Joe", "age": 17},
{"name": "Bob", "age": 17},
{"name": "Carl", "age": 35}
];
var ages = uniqueBy(array, "age");
console.log(ages); // [17, 35]
const array = [ {"id":"93","name":"CVAM_NGP_KW"}, {"id":"94","name":"CVAM_NGP_PB"}, {"id":"93","name":"CVAM_NGP_KW"}, {"id":"94","name":"CVAM_NGP_PB"} ] function uniq(array, field) { return array.reduce((accumulator, current) => { if(!accumulator.includes(current[field])) { accumulator.push(current[field]) } return accumulator; }, [] ) } const ids = uniq(array, 'id'); console.log(ids) /* output ["93", "94"] */
如果您需要整个对象,这与 ES6 版本略有不同:
let arr = [
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
arr.filter((a, i) => arr.findIndex((s) => a.age === s.age) === i) // [{"name":"Joe", "age":17}, {"name":"Carl", "age": 35}]
我有一个小解决方案
let data = [{id: 1}, {id: 2}, {id: 3}, {id: 2}, {id: 3}];
let result = data.filter((value, index, self) => self.findIndex((m) => m.id === value.id) === index);
您可能对基于其中一个键的唯一对象集感兴趣:
const array = [
{"name": "Joe", "age": 17},
{"name": "Bob", "age": 17},
{"name": "Carl", "age": 35}
];
const distinctItems = [...new Map(array.map(item => [item["age"], item])).values()];
结果:
[
{name: "Bob", age: 17},
{name: "Carl", age: 35}
]
@travis-j 答案的forEach
版本(对现代浏览器和 Node JS 世界很有帮助):
var unique = {};
var distinct = [];
array.forEach(function (x) {
if (!unique[x.age]) {
distinct.push(x.age);
unique[x.age] = true;
}
});
在 Chrome v29.0.1547 上快 34%:http: //jsperf.com/filter-versus-dictionary/3
还有一个采用映射器函数的通用解决方案(比直接映射慢一点,但这是意料之中的):
function uniqueBy(arr, fn) {
var unique = {};
var distinct = [];
arr.forEach(function (x) {
var key = fn(x);
if (!unique[key]) {
distinct.push(key);
unique[key] = true;
}
});
return distinct;
}
// usage
uniqueBy(array, function(x){return x.age;}); // outputs [17, 35]
我已经开始在所有新项目中默认使用下划线,这样我就不必考虑这些小的数据处理问题。
var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}];
console.log(_.chain(array).map(function(item) { return item.age }).uniq().value());
产生[17, 35]
。
这是解决此问题的另一种方法:
var result = {};
for(var i in array) {
result[array[i].age] = null;
}
result = Object.keys(result);
或者
result = Object.values(result);
我不知道这个解决方案与其他解决方案相比有多快,但我喜欢更简洁的外观。 ;-)
编辑:好的,以上似乎是这里最慢的解决方案。
我在这里创建了一个性能测试用例:http: //jsperf.com/distinct-values-from-array
我没有测试年龄(整数),而是选择比较名称(字符串)。
方法1(TS的解决方案)非常快。 有趣的是,方法 7 优于所有其他解决方案,在这里我只是摆脱了.indexOf()
并使用了它的“手动”实现,避免了循环函数调用:
var result = [];
loop1: for (var i = 0; i < array.length; i++) {
var name = array[i].name;
for (var i2 = 0; i2 < result.length; i2++) {
if (result[i2] == name) {
continue loop1;
}
}
result.push(name);
}
使用 Safari 和 Firefox 的性能差异是惊人的,似乎 Chrome 在优化方面做得最好。
我不确定为什么上述片段与其他片段相比如此之快,也许比我更聪明的人有答案。 ;-)
使用lodash
var array = [
{ "name": "Joe", "age": 17 },
{ "name": "Bob", "age": 17 },
{ "name": "Carl", "age": 35 }
];
_.chain(array).pluck('age').unique().value();
> [17, 35]
var array = [ {"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35} ]; const ages = [...new Set(array.reduce((a, c) => [...a, c.age], []))]; console.log(ages);
const array = [ { "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 } ] const key = 'age'; const arrayUniqueByKey = [...new Map(array.map(item => [item[key], item])).values()]; console.log(arrayUniqueByKey);
使用 Maps 的简单不同过滤器:
let array = [ {"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35} ]; let data = new Map(); for (let obj of array) { data.set(obj.age, obj); } let out = [...data.values()]; console.log(out);
使用Lodash
var array = [
{ "name": "Joe", "age": 17 },
{ "name": "Bob", "age": 17 },
{ "name": "Carl", "age": 35 }
];
_.chain(array).map('age').unique().value();
返回 [17,35]
function get_unique_values_from_array_object(array,property){
var unique = {};
var distinct = [];
for( var i in array ){
if( typeof(unique[array[i][property]]) == "undefined"){
distinct.push(array[i]);
}
unique[array[i][property]] = 0;
}
return distinct;
}
underscore.js _.uniq(_.pluck(array,"age"))
这是一个使用reduce、允许映射和维护插入顺序的通用解决方案。
项目:一个数组
mapper :将项目映射到条件的一元函数,或者为空以映射项目本身。
function distinct(items, mapper) {
if (!mapper) mapper = (item)=>item;
return items.map(mapper).reduce((acc, item) => {
if (acc.indexOf(item) === -1) acc.push(item);
return acc;
}, []);
}
用法
const distinctLastNames = distinct(items, (item)=>item.lastName);
const distinctItems = distinct(items);
如果这是您的风格,您可以将其添加到您的 Array 原型中并省略items参数......
const distinctLastNames = items.distinct( (item)=>item.lastName) ) ;
const distinctItems = items.distinct() ;
您还可以使用 Set 而不是 Array 来加快匹配速度。
function distinct(items, mapper) {
if (!mapper) mapper = (item)=>item;
return items.map(mapper).reduce((acc, item) => {
acc.add(item);
return acc;
}, new Set());
}
如果您想返回一个唯一的对象列表。 这是另一种选择:
const unique = (arr, encoder=JSON.stringify, decoder=JSON.parse) =>
[...new Set(arr.map(item => encoder(item)))].map(item => decoder(item));
这将变成这样:
unique([{"name": "john"}, {"name": "sarah"}, {"name": "john"}])
进入
[{"name": "john"}, {"name": "sarah"}]
这里的技巧是,我们首先使用JSON.stringify
将项目编码为字符串,然后将其转换为 Set(这使得字符串列表唯一),然后我们使用JSON.parse
。
var array = [ {"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35} ] console.log(Object.keys(array.reduce((r,{age}) => (r[age]='', r) , {})))
输出:
Array ["17", "35"]
刚找到这个,我认为它很有用
_.map(_.indexBy(records, '_id'), function(obj){return obj})
再次使用下划线,所以如果你有这样的对象
var records = [{_id:1,name:'one', _id:2,name:'two', _id:1,name:'one'}]
它只会给你独特的对象。
这里发生的是indexBy
返回这样的地图
{ 1:{_id:1,name:'one'}, 2:{_id:2,name:'two'} }
仅仅因为它是一张地图,所有的键都是唯一的。
然后我只是将此列表映射回数组。
如果您只需要不同的值
_.map(_.indexBy(records, '_id'), function(obj,key){return key})
请记住, key
作为字符串返回,因此,如果您需要整数,则应该这样做
_.map(_.indexBy(records, '_id'), function(obj,key){return parseInt(key)})
我认为您正在寻找 groupBy 功能(使用 Lodash)
_personsList = [{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}];
_uniqAgeList = _.groupBy(_personsList,"age");
_uniqAges = Object.keys(_uniqAgeList);
产生结果:
17,35
jsFiddle 演示:http: //jsfiddle.net/4J2SX/201/
[...new Set([
{ "name": "Joe", "age": 17 },
{ "name": "Bob", "age": 17 },
{ "name": "Carl", "age": 35 }
].map(({ age }) => age))]
如果您有 Array.prototype.includes 或愿意对其进行polyfill ,则可以:
var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.age); });
如果像我一样,你更喜欢“功能性”而不影响速度,这个例子使用包含在 reduce 闭包中的快速字典查找。
var array =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
var uniqueAges = array.reduce((p,c,i,a) => {
if(!p[0][c.age]) {
p[1].push(p[0][c.age] = c.age);
}
if(i<a.length-1) {
return p
} else {
return p[1]
}
}, [{},[]])
根据这个测试,我的解决方案比建议的答案快两倍
我知道我的代码很短,时间复杂度也很低,但这是可以理解的,所以我尝试了这种方式。
我正在尝试在这里开发基于原型的功能,代码也发生了变化。
这里,Distinct 是我自己的原型函数。
<script> var array = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 } ] Array.prototype.Distinct = () => { var output = []; for (let i = 0; i < array.length; i++) { let flag = true; for (let j = 0; j < output.length; j++) { if (array[i].age == output[j]) { flag = false; break; } } if (flag) output.push(array[i].age); } return output; } //Distinct is my own function console.log(array.Distinct()); </script>
假设我有以下内容:
var array =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
能够获得所有不同年龄的数组的最佳方法是什么,这样我就可以得到以下结果数组:
[17, 35]
是否有某种方法可以替代性地构造数据或更好的方法,从而使我不必遍历每个数组来检查“ age”的值并检查另一个数组是否存在,如果没有,则添加它?
如果有某种方法,我可以不重复地抽出不同的年龄...
我想改善当前无效的方法...如果这意味着不是“数组”是对象数组,而是带有一些唯一键(即“ 1,2,3”)的对象“映射”也可以我只是在寻找最高效的方式。
以下是我目前的操作方式,但是对我来说,即使迭代确实有效,迭代似乎也很糟糕。
var distinct = []
for (var i = 0; i < array.length; i++)
if (array[i].age not in distinct)
distinct.push(array[i].age)
如果您需要整个对象的唯一性
const _ = require('lodash');
var objects = [
{ 'x': 1, 'y': 2 },
{ 'y': 1, 'x': 2 },
{ 'x': 2, 'y': 1 },
{ 'x': 1, 'y': 2 }
];
_.uniqWith(objects, _.isEqual);
[对象{x: 1, y: 2}, 对象{x: 2, y: 1}]
这里有很多很好的答案,但没有一个解决以下问题:
有什么方法可以替代地构造数据
我会创建一个对象,其键是年龄,每个对象都指向一个名称数组。
var array = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 }]; var map = array.reduce(function(result, item) { result[item.age] = result[item.age] || []; result[item.age].push(item.name); return result; }, {}); console.log(Object.keys(map)); console.log(map);
通过这种方式,您已将数据结构转换为一种很容易从中检索不同年龄的数据结构。
这是一个更紧凑的版本,它也存储整个对象,而不仅仅是名称(如果您正在处理具有 2 个以上属性的对象,因此它们不能存储为键和值)。
var array = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 }]; var map = array.reduce((r, i) => ((r[i.age] = r[i.age] || []).push(i), r), {}); console.log(Object.keys(map)); console.log(map);
原始类型
var unique = [...new Set(array.map(item => item.pritiveAttribute))];
对于复杂类型,例如对象
var unique = [...new DeepSet(array.map(item => item.Object))];
export class DeepSet extends Set {
add (o: any) {
for (let i of this)
if (this.deepCompare(o, i))
return this;
super.add.call(this, o);
return this;
};
private deepCompare(o: any, i: any) {
return JSON.stringify(o) === JSON.stringify(i)
}
}
const array = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 } ] const uniqueArrayByProperty = (array, callback) => { return array.reduce((prev, item) => { const v = callback(item); if (!prev.includes(v)) prev.push(v) return prev }, []) } console.log(uniqueArrayByProperty(array, it => it.age));
我下面的代码将显示唯一的年龄数组,以及没有重复年龄的新数组
var data = [
{"name": "Joe", "age": 17},
{"name": "Bob", "age": 17},
{"name": "Carl", "age": 35}
];
var unique = [];
var tempArr = [];
data.forEach((value, index) => {
if (unique.indexOf(value.age) === -1) {
unique.push(value.age);
} else {
tempArr.push(index);
}
});
tempArr.reverse();
tempArr.forEach(ele => {
data.splice(ele, 1);
});
console.log('Unique Ages', unique);
console.log('Unique Array', data);```
有一个库提供打字稿中的强类型可查询集合 。
集合是:
该库称为ts-generic-collections 。
GitHub上的源代码:
https://github.com/VeritasSoftware/ts-generic-collections
您可以得到如下所示的不同值
it('distinct', () => {
let numbers: number[] = [1, 2, 3, 1, 3];
let list = new List(numbers);
let distinct = list.distinct(new EqualityComparer());
expect(distinct.length == 3);
expect(distinct.elementAt(0) == 1);
expect(distinct.elementAt(1) == 2);
expect(distinct.elementAt(2) == 3);
});
class EqualityComparer implements IEqualityComparer<number> {
equals(x: number, y: number) : boolean {
return x == y;
}
}
回答这个老问题毫无意义,但有一个简单的答案可以说明 Javascript 的本质。 Javascript 中的对象本质上是哈希表。 我们可以使用它来获取唯一键的散列:
var o = {}; array.map(function(v){ o[v.age] = 1; });
然后我们可以将哈希减少到一个唯一值数组:
var a2 = []; for (k in o){ a2.push(k); }
这就是你所需要的。 数组a2只包含唯一的年龄。
const array = [ { "name": "Joe", "age": 17 }, { "name":"Bob", "age":17 }, { "name":"Carl", "age": 35 } ] const allAges = array.map(a => a.age); const uniqueSet = new Set(allAges) const uniqueArray = [...uniqueSet] console.log(uniqueArray)
有linq.js - LINQ for JavaScript包(npm install linq),对于 .Net 开发人员来说应该很熟悉。
在 示例中显示的其他方法中,有明显的重载。
通过对象数组中的属性值区分对象的示例是
Enumerable.from(array).distinct(“$.id”).toArray();
来自https://medium.com/@xmedeko/i-recommend-you-to-try-https-github-com-mihaifm-linq-20a4e3c090e9
我随机抽取样本并针对 100,000 个项目进行测试,如下所示:
let array=[]
for (var i=1;i<100000;i++){
let j= Math.floor(Math.random() * i) + 1
array.push({"name":"Joe"+j, "age":j})
}
这里是每个的性能结果:
Vlad Bezden Time: === > 15ms
Travis J Time: 25ms === > 25ms
Niet the Dark Absol Time: === > 30ms
Arun Saini Time: === > 31ms
Mrchief Time: === > 54ms
Ivan Nosov Time: === > 14374ms
另外,我想提一下,由于项目是随机生成的,第二名是在 Travis 和 Niet 之间迭代。
假设我们有这样的数据arr=[{id:1,age:17},{id:2,age:19} ...]
,然后我们可以找到这样的独特对象 -
function getUniqueObjects(ObjectArray) {
let uniqueIds = new Set();
const list = [...new Set(ObjectArray.filter(obj => {
if (!uniqueIds.has(obj.id)) {
uniqueIds.add(obj.id);
return obj;
}
}))];
return list;
}
在此处查看Codepen 链接
@Travis J Typescript 类型安全功能方法中的字典答案
const uniqueBy = <T, K extends keyof any>(
list: T[] = [],
getKey: (item: T) => K,
) => {
return list.reduce((previous, currentItem) => {
const keyValue = getKey(currentItem)
const { uniqueMap, result } = previous
const alreadyHas = uniqueMap[keyValue]
if (alreadyHas) return previous
return {
result: [...result, currentItem],
uniqueMap: { ...uniqueMap, [keyValue]: true }
}
}, { uniqueMap: {} as Record<K, any>, result: [] as T[] }).result
}
const array = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 }];
console.log(uniqueBy(array, el => el.age))
// [
// {
// "name": "Joe",
// "age": 17
// },
// {
// "name": "Carl",
// "age": 35
// }
// ]
unique(obj, prop) {
let result = [];
let seen = new Set();
Object.keys(obj)
.forEach((key) => {
let value = obj[key];
let test = !prop
? value
: value[prop];
!seen.has(test)
&& seen.add(test)
&& result.push(value);
});
return result;
}
我知道这是一个古老且相对较易回答的问题,我给出的答案将使完整对象重新获得(我在这篇文章的很多评论中都看到了这一点)。 它可能是“粘性”的,但是就可读性而言,它比许多其他解决方案更干净(尽管效率更低)。
这将返回数组内部完整对象的唯一数组。
let productIds = data.map(d => {
return JSON.stringify({
id : d.sku.product.productId,
name : d.sku.product.name,
price : `${d.sku.product.price.currency} ${(d.sku.product.price.gross / d.sku.product.price.divisor).toFixed(2)}`
})
})
productIds = [ ...new Set(productIds)].map(d => JSON.parse(d))```
我用TypeScript编写了自己的Array.distinctBy {}
,以Array.distinctBy {}
一般情况,例如Kotlin的Array.distinctBy {}
...
function distinctBy<T, U extends string | number>(array: T[], mapFn: (el: T) => U) {
const uniqueKeys = new Set(array.map(mapFn));
return array.filter((el) => uniqueKeys.has(mapFn(el)));
}
当然,在哪里U
是可哈希的。 对于对象,您可能需要https://www.npmjs.com/package/es6-json-stable-stringify
那么你可以使用 lodash 来编写一个不那么冗长的代码
方法一:嵌套方法
let array =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
let result = _.uniq(_.map(array,item=>item.age))
方法 2:方法链或级联方法
let array =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
let result = _.chain(array).map(item=>item.age).uniq().value()
您可以从https://lodash.com/docs/4.17.15#uniq了解 lodash 的 uniq() 方法
从一组键中获取不同值集合的方法。
您可以从此处获取给定的代码,并仅添加所需键的映射以获取唯一对象值的数组。
const listOfTags = [{ id: 1, label: "Hello", color: "red", sorting: 0 }, { id: 2, label: "World", color: "green", sorting: 1 }, { id: 3, label: "Hello", color: "blue", sorting: 4 }, { id: 4, label: "Sunshine", color: "yellow", sorting: 5 }, { id: 5, label: "Hello", color: "red", sorting: 6 }], keys = ['label', 'color'], filtered = listOfTags.filter( (s => o => (k => !s.has(k) && s.add(k)) (keys.map(k => o[k]).join('|')) )(new Set) ) result = filtered.map(o => Object.fromEntries(keys.map(k => [k, o[k]]))); console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
使用集合和过滤器。 这保留了顺序:
let unique = (items) => { const s = new Set(); return items.filter((item) => { if (s.has(item)) { return false; } s.add(item); return true; }); } console.log( unique( [ 'one', 'two', 'two', 'three', 'three', 'three' ] ) ); /* output: [ "one", "two", "three" ] */
如果您一直使用 ES5,或者由于某种原因无法使用new Set
或new Map
,并且您需要一个包含具有唯一键的值的数组(而不仅仅是唯一键的数组),则可以使用以下命令:
function distinctBy(key, array) {
var keys = array.map(function (value) { return value[key]; });
return array.filter(function (value, index) { return keys.indexOf(value[key]) === index; });
}
或者 TypeScript 中的类型安全等价物:
public distinctBy<T>(key: keyof T, array: T[]) {
const keys = array.map(value => value[key]);
return array.filter((value, index) => keys.indexOf(value[key]) === index);
}
用法:
var distinctPeople = distinctBy('age', people);
所有其他答案要么:
new Set
、 new Map
等;.age
硬编码到不同的函数中);这个答案没有上述四个问题中的任何一个。
如果您的数组是对象数组,则可以使用此代码。
getUniqueArray = (array: MyData[]) => {
return array.filter((elem, index) => array.findIndex(obj => obj.value == elem.value) === index);
}
MyData 如下所示:
export interface MyData{
value: string,
name: string
}
注意:您不能使用 Set,因为当比较对象时,它们是按引用而不是按值进行比较。 因此,您需要比较对象的唯一键,在我的示例中,唯一键是值字段。 有关更多详细信息,您可以访问此链接: 在 Javascript 中过滤唯一值的数组
let mobilePhones = [{id: 1, brand: "B1"}, {id: 2, brand: "B2"}, {id: 3, brand: "B1"}, {id: 4, brand: "B1"}, {id: 5, brand: "B2"}, {id: 6, brand: "B3"}] let allBrandsArr = mobilePhones .map(row=>{ return row.brand; }); let uniqueBrands = allBrandsArr.filter((item, index, arry) => (arry.indexOf(item) === index)); console.log('uniqueBrands ', uniqueBrands );
使用iter-ops库的高效和干净的方法:
import {pipe, distinct, map} from 'iter-ops';
const array =
[
{name: 'Joe', age: 17},
{name: 'Bob', age: 17},
{name: 'Carl', age: 35}
];
const i = pipe(
array,
distinct(a => a.age),
map(m => m.age)
);
const uniqueAges = [...i]; //=> [17, 35]
现在我们可以在相同的键和相同的值的基础上唯一的 Object
const arr = [{"name":"Joe", "age":17},{"name":"Bob", "age":17}, {"name":"Carl", "age": 35},{"name":"Joe", "age":17}]
let unique = []
for (let char of arr) {
let check = unique.find(e=> JSON.stringify(e) == JSON.stringify(char))
if(!check) {
unique.push(char)
}
}
console.log(unique)
////outPut::: [{ name: "Joe", age: 17 }, { name: "Bob", age: 17 },{ name: "Carl", age: 35 }]
如果您想遍历独特的项目,请使用:
(更灵活的版本https://stackoverflow.com/a/58429784/12496886 )
const uniqBy = (arr, selector = (item) => item) => { const map = new Map(); arr.forEach((item) => { const prop = selector(item); if (.map.has(prop)) map,set(prop; item); }). return [...map;values()], } const uniqItems = uniqBy(array. (item) => item;age). console:log('uniqItems, '; uniqItems);
如果您只需要唯一值,请使用:
(与https://stackoverflow.com/a/35092559/12496886重复,仅出于完整性考虑)
const array = [ {"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}, ]; const uniq = (items) => [...new Set(items)]; const uniqAges = uniq(array.map((item) => item.age)); console.log('uniqAges: ', uniqAges);
目前正在使用 typescript 库以 orm 方式查询 js 对象。 您可以从以下链接下载。 这个答案解释了如何使用下面的库来解决。
https://www.npmjs.com/package/@krishnadaspc/jsonquery?activeTab=readme
var ageArray =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
const ageArrayObj = new JSONQuery(ageArray)
console.log(ageArrayObj.distinct("age").get()) // outputs: [ { name: 'Bob', age: 17 }, { name: 'Carl', age: 35 } ]
console.log(ageArrayObj.distinct("age").fetchOnly("age")) // outputs: [ 17, 35 ]
Runkit 直播链接: https ://runkit.com/pckrishnadas88/639b5b3f8ef36f0008b17512
export abstract class Serializable<T> {
equalTo(t: Serializable<T>): boolean {
return this.hashCode() === t.hashCode();
}
hashCode(): string {
throw new Error('Not Implemented');
}
}
export interface UserFields {
firstName: string;
lastName: string;
}
export class User extends Serializable<User> {
constructor(private readonly fields: UserFields) {
super();
}
override hashCode(): string {
return `${this.fields.firstName},${this.fields.lastName}`;
}
}
const list: User[] = [
new User({ firstName: 'first', lastName: 'user' }),
new User({ firstName: 'first', lastName: 'user' }),
new User({ firstName: 'second', lastName: 'user' }),
new User({ firstName: 'second', lastName: 'user' }),
new User({ firstName: 'third', lastName: 'user' }),
new User({ firstName: 'third', lastName: 'user' }),
];
/**
* Let's create an map
*/
const userHashMap = new Map<string, User>();
/**
* We are adding each user into the map using user's hashCode value
*/
list.forEach((user) => userHashMap.set(user.hashCode(), user));
/**
* Then getting the list of users from the map,
*/
const uniqueUsers = [...userHashMap.values()];
/**
* Let's print and see we did right?
*/
console.log(uniqueUsers.map((e) => e.hashCode()));
我对这个功能的两美分:
var result = [];
for (var len = array.length, i = 0; i < len; ++i) {
var age = array[i].age;
if (result.indexOf(age) > -1) continue;
result.push(age);
}
您可以在这里看到结果(方法8) http://jsperf.com/distinct-values-from-array/3
使用新的Ecma功能很棒,但并非所有用户都可用。
以下代码将向全局数组对象附加一个名为独特的新函数。 如果尝试获取对象数组的不同值,则可以传递值的名称以获取该类型的不同值。
Array.prototype.distinct = function(item){ var results = [];
for (var i = 0, l = this.length; i < l; i++)
if (!item){
if (results.indexOf(this[i]) === -1)
results.push(this[i]);
} else {
if (results.indexOf(this[i][item]) === -1)
results.push(this[i][item]);
}
return results;};
在CodePen中查看我的帖子以获取演示。
你试一试
var x = [] ;
for (var i = 0 ; i < array.length ; i++)
{
if(x.indexOf(array[i]['age']) == -1)
{
x.push(array[i]['age']);
}
}
console.log(x);
如果您想从已知唯一对象属性的数组中过滤掉重复值,您可以使用以下代码片段:
let arr = [
{ "name": "Joe", "age": 17 },
{ "name": "Bob", "age": 17 },
{ "name": "Carl", "age": 35 },
{ "name": "Carl", "age": 35 }
];
let uniqueValues = [...arr.reduce((map, val) => {
if (!map.has(val.name)) {
map.set(val.name, val);
}
return map;
}, new Map()).values()]
这个函数可以唯一的数组和对象
function oaunic(x,n=0){
if(n==0) n = "elem";
else n = "elem."+n;
var uval = [];
var unic = x.filter(function(elem, index, self){
if(uval.indexOf(eval(n)) < 0){
uval.push(eval(n));
return index == self.indexOf(elem);
}
})
return unic;
}
像这样使用
tags_obj = [{name:"milad"},{name:"maziar"},{name:"maziar"}]
tags_arr = ["milad","maziar","maziar"]
console.log(oaunic(tags_obj,"name")) //for object
console.log(oaunic(tags_arr)) //for array
使用d3.js v3 :
ages = d3.set(
array.map(function (d) { return d.age; })
).values();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.