假设我有以下内容:

var array = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35}
    ]

获得所有不同年龄的数组的最佳方法是什么,这样我就得到了一个结果数组:

[17, 35]

是否有一些方法,我可以选择结构数据或更好的方法,这样我就不必遍历每个数组检查“年龄”的值,并检查另一个数组是否存在,如果没有添加它?

如果有某种方法可以让我不用迭代就能得到不同的年龄……

目前效率低下的方式,我想改进…如果它的意思不是“数组”是一个对象的数组,而是一个对象的“映射”与一些唯一的键(即。"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)

当前回答

简单独特的过滤器使用地图:

Let array = [ {" name ":“乔”,“年龄”:17}, {" name ":“鲍勃”、“年龄”:17}, {"name":"Carl", "age": 35} ]; let data = new Map(); For (let obj of array) { data.set (obj。年龄、obj); } Let out =[…data.values()]; console.log(出);

其他回答

这里有另一种解决方法:

var result = {};
for(var i in array) {
    result[array[i].age] = null;
}

result = Object.keys(result);

or

result = Object.values(result);

我不知道这个解决方案与其他解决方案相比有多快,但我喜欢更干净的外观。:-)


编辑:好吧,上面的似乎是最慢的解决方案。

我在这里创建了一个性能测试用例:http://jsperf.com/distinct-values-from-array

我没有测试年龄(整数),而是选择比较名称(字符串)。

方法1 (TS的解决方案)非常快。有趣的是,Method 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在优化方面做得最好。

我不太确定为什么上面的片段比其他片段快,也许比我更聪明的人有答案。:-)

目前正在使用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 live链接:https://runkit.com/pckrishnadas88/639b5b3f8ef36f0008b17512

您可以使用像这样的字典方法。基本上,你在“字典”中指定你想要不同的值作为键(这里我们使用数组作为对象以避免使用字典模式)。如果该键不存在,则将该值添加为distinct。

下面是一个工作演示:

数组var =[{“名称”:“乔”,“年龄”:17},{“名称”:“鲍勃”,“年龄”:17},{“名称”:“卡尔”,“年龄”:35}); Var unique = []; Var distinct = []; 对于(设I = 0;I < array.length;我+ +){ 如果(!独特[array[我].age]) { distinct.push(数组[我].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%快。

清洁解决方案

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 =[{“名称”:“乔”,“年龄”:17},{“名称”:“鲍勃”,“年龄”:17},{“名称”:“卡尔”,“年龄”:35}); Var map =数组。Reduce(函数(结果,项){ 结果项目。年龄= result[item.]年龄:|| []; 结果[item.age] .push (item.name); 返回结果; }, {}); console.log(种(地图)); console.log(地图);

通过这种方式,您已经将数据结构转换为非常容易从中检索不同年龄的结构。

这里有一个更紧凑的版本,它也存储了整个对象,而不仅仅是名称(如果你处理的对象有超过2个属性,所以它们不能存储为键和值)。

数组var =[{“名称”:“乔”,“年龄”:17},{“名称”:“鲍勃”,“年龄”:17},{“名称”:“卡尔”,“年龄”:35}); Var map =数组。Reduce ((r, i) => ((r[i])年龄]= r[i。年龄:|| []).push(i), r), {}); console.log(种(地图)); console.log(地图);