如何在JavaScript中从一个对象数组中获取不同的值?

842
假设我有以下内容:
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)

74
迭代不是“效率低下的”,你不能“不迭代”就对每个元素进行操作。虽然你可以使用各种看起来像函数式的方法,但最终某个层面上的东西仍需要遍历项。 - Eevee
//100% 运行代码 const listOfTags = [{ id: 1, label: "你好", color: "红色", sorting: 0 }, { id: 2, label: "世界", color: "绿色", sorting: 1 }, { id: 3, label: "你好", color: "蓝色", sorting: 4 }, { id: 4, label: "阳光", color: "黄色", sorting: 5 }, { id: 5, label: "你好", color: "红色", 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) );console.log(filtered); - Sandeep Mishra
1
赏金很高,但是使用给定数据和答案的问题已经在这里回答了:https://dev59.com/TlQJ5IYBdhLWcg3wlm7B。那么赏金的目的是什么?我应该用两个或更多键来回答这个特定的问题吗? - Nina Scholz
1
Set 对象和 map 是浪费的。这个任务只需要一个简单的 .reduce() 阶段即可。 - Redu
请查看此示例,https://stackoverflow.com/a/58944998/13013258。 - Kezia Rose
/答案:/ var ListDistinct=[]; array.forEach((m)=>{ if(ListDistinct.indexOf(m.age)<0)ListDistinct.push(m.age); }); console.log(ListDistinct); - garish
65个回答

0

高效且简洁的方法,使用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]

0
我建议最简单的方法是通过在元素数组顶部创建一个对象,通过该对象可以按字段获取所有唯一/不同的元素。 例如。
const getDistinct = (arr = [], field) => {
    const distinctMap = {};
    arr.forEach(item => {
        if(!distinctMap[item[field]]) {
            distinctMap[item[field]] = item;
        }
    });
    const distinctFields = Object.keys(distinctMap);
    const distinctElements = Object.values(distinctMap);
    return {distinctFields, distinctElements}
}
const array = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35}
    ]
console.log(JSON.stringify(getDistinct(array, "age")));
/*output will be => 
  {
    distinctFields: ["17", "35"],
    distinctElements: [
      { name: "Joe", age: 17 },
      { name: "Carl", age: 35 }
    ]
  }*/

0

如果你的数组是对象数组,你可以使用这段代码。

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,因为当对象进行比较时,是通过引用而不是值进行比较的。因此,你需要一个唯一的键来比较对象,在我的例子中,唯一键是value字段。 要了解更多详情,请访问此链接:在Javascript中过滤数组以获取唯一值

0

使用新的 Ecma 特性很棒,但并非所有用户都可用。

以下代码将向全局数组对象附加一个名为distinct的新函数。 如果您正在尝试获取对象数组的不同值,则可以传递该类型的值的名称以获取不同的值。

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中的我的帖子以获取演示。


这绝对是最快速和最可重复的方法。 - Achilles
http://jsbench.github.io/#e6f583e740e107b4f6eabd655114f35d 可以展示该方法比其他方法运行快70%左右。 - Achilles

0

从一组键中获取不同值的方法。

您可以从这里获取给定代码,并添加仅针对所需键的映射,以获取唯一对象值的数组。

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; }


0
使用 set 和 filter。这将保留顺序:

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"
]
*/


0

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 );


0

如果你被困在使用ES5中,或者由于某些原因不能使用new Setnew 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);

所有其他答案要么:
  • 返回唯一键的数组,而不是对象(例如返回年龄列表,而不是具有唯一年龄的人);
  • 使用 ES6、new Setnew Map 等可能不可用的内容;
  • 没有可配置的键(例如将 .age 硬编码到 distinct 函数中);
  • 假设可以使用键索引数组,这并不总是正确的,TypeScript 不会允许。

此答案没有以上四个问题。


0

你可以使用lodash编写更简洁的代码。

方法1:嵌套方法

    let array = 
        [
            {"name":"Joe", "age":17}, 
            {"name":"Bob", "age":17}, 
            {"name":"Carl", "age": 35}
        ]
    let result = _.uniq(_.map(array,item=>item.age))

方法二:方法链或级联方法

    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()方法的信息。


-1

关于这个函数,我想说两句:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接