programing

JavaScript에서 개체 배열과 다른 값을 얻는 방법

yoursource 2023. 1. 15. 13:05
반응형

JavaScript에서 개체 배열과 다른 값을 얻는 방법

다음과 같은 것이 있다고 가정합니다.

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

다음과 같은 결과 배열을 얻을 수 있도록 모든 연령의 배열을 얻을 수 있는 가장 좋은 방법은 무엇입니까?

[17, 35]

각 어레이에서 "age" 값을 체크하고 다른 어레이와 대조하여 존재 여부를 확인하고 그렇지 않은 경우 추가할 필요가 없도록 데이터 구조화 또는 더 나은 방법을 선택할 수 있습니까?

반복하지 않고 뚜렷한 나이를 뽑아낼 수 있는 방법이 있다면...

현재의 비효율적인 방법을 개선하고 싶다..."array"가 객체의 배열이 아니라 "map"이 객체의 고유한 키(즉, "1, 2, 3")를 갖는 객체의 "map"을 의미한다면 그것도 괜찮습니다.가장 퍼포먼스가 뛰어난 방법을 찾고 있습니다.

다음은 제가 현재 하고 있는 방법입니다만, 저는 반복이 효과가 있어도 효율성은 떨어지는 것 같습니다.

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라면 "PHP"를 array_keysJS에 의한 것입니다.대신 다음과 같이 시도해 보십시오.

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

이와 같은 사전적 접근 방식을 사용할 수 있습니다.기본적으로 "dictionary"에서 구별하는 값을 키로 할당합니다(여기에서는 사전 모드를 피하기 위해 어레이를 개체로 사용합니다).키가 존재하지 않으면 해당 값을 고유하게 추가합니다.

다음은 작업 데모입니다.

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)보다 빠른 방법은 없습니다.

이전 버전에서는 in에 대해 오브젝트를 사용했습니다.이것들은 성격상 경미하고, 그 후 상기의 마이너 갱신이 행해지고 있습니다.그러나 원본 jsperf의 두 버전 간에 성능이 향상되는 것처럼 보이는 이유는 데이터 샘플 크기가 너무 작았기 때문입니다.따라서 이전 버전의 주요 비교는 내부 맵과 필터 사용의 차이와 사전 모드 검색의 차이였습니다.

상기의 코드를 갱신했습니다만, 3.3에서는 퍼포먼스 함정의 많은 부분을 간과하고 있었습니다(구식 jsperf).

성능

https://jsperf.com/filter-vs-dictionary-more-data 제가 이 사전을 실행했을 때 96% 더 빨랐습니다.

필터와 사전

2017년 8월 25일 현재 ES6를 통해 새로운 Set을 사용하여 이 문제를 해결할 수 있습니다.

타입 스크립트

 Array.from(new Set(yourArray.map((item: any) => item.id)))

JS

 Array.from(new Set(yourArray.map((item) => item.id)))

매핑하고 dups를 삭제하기만 하면 됩니다.

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입니다.마이크로 최적화에 관심이 있거나 대량의 데이터가 있는 경우 일반 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);

forEach@ 및 월드에 이 됩니다):@travis-j 응답 버전(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

연령(Integers)에 대한 테스트 대신 이름(Strings)을 비교하기로 했습니다.

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의 성능 차이는 놀라울 정도로 크롬이 최적화를 가장 잘 하는 것 같습니다.

위의 스니펫이 다른 스니펫에 비해 왜 이렇게 빠른지 잘 모르겠습니다.저보다 현명한 분이 답을 알고 계실지도 모릅니다.;-)

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

맵을 사용한 간단한 고유 필터:

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

언더스코어.삭제_.uniq(_.pluck(array,"age"))

다음은 reduce를 사용하고 매핑을 허용하며 삽입 순서를 유지하는 범용 솔루션입니다.

항목: 배열

매퍼: 항목을 기준에 매핑하는 단항 함수 또는 항목 자체를 매핑하려면 비워 둡니다.

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

어레이 프로토타입에 추가할 수 있습니다.고객의 스타일이라면 items 파라미터는 생략할 수 있습니다.

const distinctLastNames = items.distinct( (item)=>item.lastName) ) ;
const distinctItems = items.distinct() ;

배열 대신 집합을 사용하여 일치 속도를 높일 수도 있습니다.

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그 후 그것을 세트(문자열 목록을 고유하게 함)로 변환하고, 그 후 를 사용하여 원래 개체로 되돌립니다.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))]

원시 유형

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

언급URL : https://stackoverflow.com/questions/15125920/how-to-get-distinct-values-from-an-array-of-objects-in-javascript

반응형