배열에서 중복 제거


100

다음과 같은 개체 배열이 있습니다.

var array = [
    {id:123, value:"value1", name:"Name1"},
    {id:124, value:"value2", name:"Name1"},
    {id:125, value:"value3", name:"Name2"},
    {id:126, value:"value4", name:"Name2"}
    ...
];

보시다시피 일부 이름은 반복됩니다. 이름 만있는 새 배열을 얻고 싶지만 일부 이름이 반복되면 다시 추가하고 싶지 않습니다. 이 배열을 원합니다.

var newArray = ["Name1", "Name2"];

나는 이것을 시도하고있다 map:

var newArray = array.map((a) => {
    return a.name;
});

그러나 문제는 이것이 반환된다는 것입니다.

newArray = ["Name1", "Name1", "Name2", "Name2"];

내부 map에 조건을 설정 하여 이미 존재하는 요소를 반환하지 않도록하려면 어떻게해야합니까? 이 작업을 map다른 ECMAScript 5 또는 ECMAScript 6 기능 으로 수행하고 싶습니다 .


2
그런 다음 어레이에서 중복을 제거하십시오.
Tushar



id : 125가 포함 된 줄이 쉼표로 끝나지 않는 이유는 무엇입니까?
Peter Mortensen

.indexOf ()를 사용하는 모든 답변 은 2 차 시간 복잡성 으로 인해 배열이 크면 성능저하됩니다 . ES6 세트를 사용하거나 ES5 객체 를 사전으로 사용하는 것이 좋습니다 .
joeytwiddle

답변:


210

ES6를 사용 Set하면 개체의 이름 만 매핑 한 후 고유 한 값을 사용할 수 있습니다 .

이 제안은 새 배열에서 항목을 수집하기 위해 스프레드 구문... 을 사용합니다 .

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }],
      names = [...new Set(array.map(a => a.name))];

console.log(names);


9
내 정보를 위해 .. 무엇을 ...합니까?
Rajshekar Reddy

9
@RajshekarReddy, 반복 가능한 객체로 배열을 구축하기위한 확산 구문... 입니다.
Nina Scholz

5
나는 "Set"자체에 대해 찬성하는 것이 아니라 스프레드 연산자의 현명한 사용을 위해 찬성하는 것입니다. 새로운 것을 배우거나 실제 사례에 적용된 새로운 것을 보는 것은 항상 좋은 일이므로이 게시물은 찬성 할 가치가 있습니다.
briosheje

33
그것은 내 개인적인 의견이지만 다소 일반적인 의견 입니다. 사용 Array.from은 변환의 의도를 훨씬 더 잘 전달하고 (또한 초보자를위한 이해 / 검색이 더 쉬움), 확산 구문은 확산 된 요소가 여러 요소 중 하나 인 경우에만 사용해야합니다. 아마도 그것을 "나쁜 관행"이라고 부르는 것은 너무 가혹합니다. 미안합니다. 단지 그것이 일반적인 관용구가되는 것을 막고 싶습니다.
Bergi

3
@KRyan은 ES6가 그렇게 새롭습니까? 2015 년 6 월에 마무리되었습니다. 그것은의 시간이 새로운 기능을 이해하고 사용하려면
edc65

64

ES 6 (Set 없음)이 아닌 JavaScript 솔루션을 찾고 있다면 Array의 reduce방법을 사용할 수 있습니다 .

var array=[
  {id:123, value:"value1", name:"Name1"},
  {id:124, value:"value2", name:"Name1"},
  {id:125, value:"value3", name:"Name2"},
  {id:126, value:"value4", name:"Name2"}
];
var names = array.reduce(function (a, b) {
  if (a.indexOf(b.name) == -1) {
    a.push(b.name)
  }
  return a;
}, []);

console.log(names);


2
이 답변은 또한 중간 배열이나 집합, 특히 이름 자체 만 포함하는 집합이 필요하지 않다는 이점이 있습니다. (객체 배열에서 객체 배열로 직접 이동합니다.) +1
jpmc26

@Iwrestledabearonce,이 두 번째 매개 변수는 반환 된 매개 변수와 동일한 객체가 아닙니까?
Kaiido

네,하지만 정렬이나 필터처럼 하나에서 다른 곳으로 곧바로 가지 않습니다. 빈 배열에서 다시 만들어졌습니다.
곰과 레슬링 한 적이 있습니다.

1
@Dekel - 작은 버전 :var names = array.reduce(function(a, b) { a.indexOf(b.name) === -1 && a.push(b.name) return a; }, []);
레이온

3
@Rayon 소스 코드의 크기에 너무 많은 관심을 기울이지 마십시오. 이것은 많은 자작 프로그래머에게 일반적인 함정이며 가장 중요한 것은 프로그램이 효율적이고 읽기 쉬워야한다는 것입니다.
leaf

16

개인적으로 모든 사람들이 ES 6을 좋아하는 이유를 모르겠습니다. 이것이 제 코드라면 가능한 한 많은 브라우저를 지원하고 싶습니다.

var array=[
{id:123, value:"value1", name:"Name1"},
{id:124, value:"value2", name:"Name1"},
{id:125, value:"value3", name:"Name2"},
{id:126, value:"value4", name:"Name2"}
];

   // Create array of unique names
var a = (function(a){
  for (var i = array.length; i--;)
    if (a.indexOf(array[i].name) < 0) a.push(array[i].name);
  return a;
})([]);

console.log(a);


2
indexOf항상 -ing 대신 객체를 사전으로 사용하는 것이 더 성능이 좋지 않을까요? 예 : do added[name] = trueand if(added[name])대신 if(a.indexOf(name)).
Bojidar Marinov

7
"개인적으로 나는 왜 모든 사람들이 es6로 모든 것을 좋아하는지 알지 못합니다."왜 당신은를 구하고 goto fail, 색인 변수를 둘러싸는 범위로 유출하고 있는지 등. 이전 브라우저를 위해 폴리 필 / 변환하기 쉬운 부분입니다.
자레드 스미스

5
더 읽기 쉬운가요? 항목을 배열로 푸시하는 그것의 이상한 for 루프입니다. 훨씬 더 읽기보다 얻을 나던 ...
나는 곰을 한 번 씨름.

4
솔직히 말해서 불평 할 무언가를 찾기 위해 너무 열심히 노력하는 것 같습니다.
곰과 레슬링 한 적이 있습니다.

2
"저는 유명한 Apple SSL 버그를 언급하고 있습니다."-당신이 그냥 가서 문맥을 벗어난 임의의 주석으로 언급하고 사람들이 그것을 인식 할 것이라고 기대할 수 있다는 것은 그렇게 유명하지 않습니다.
Hejazzman

14

또한 단순히 결합 수 mapfilter

var array = [
  {id:123, value:"value1", name:"Name1"},
  {id:124, value:"value2", name:"Name1"},
  {id:125, value:"value3", name:"Name2"},
  {id:126, value:"value4", name:"Name2"}
];

var unique = array
  .map( item => item.name )
  .filter( ( item, idx, arr ) => arr.indexOf( item ) == idx ) 

console.log(unique)


11

Object.keys () 를 사용 하여 키가 파괴 된 이름 인 Array.prototype.reduce () 를 사용하여 반복 array변수 의 객체 결과에서 주어진 객체의 고유 한 열거 가능한 속성 이름의 배열을 가져올 수 있습니다.

암호:

const array = [{id:123, value:"value1", name:"Name1"}, {id:124, value:"value2", name:"Name1"}, {id:125, value:"value3", name:"Name2"}, {id:126, value:"value4", name:"Name2"}],
      names = Object.keys(array.reduce((a, { name }) => (a[name] = 1, a), {}))

console.log(names)


7

여기에 많은 좋은 답변이 있습니다. 저는 여러분에게 또 다른 관점을주기를 희망하면서 다양성을 가지고 기여하고 싶습니다.

배열은 JavaScript에서 객체 유형이므로 동시에 해시로 사용할 수 있습니다. 이 기능을 사용하면 O (n) 시간 복잡성으로 단일 감소 작업으로 수행 할 작업을 크게 단순화 할 수 있습니다.

배열 키 이외의 일부 속성을 보유하는 배열이 마음에 들지 않으면 별도의 해시 객체를 유지하는 것도 고려할 수 있습니다.

var array = [{id:123, value:"value1", name:"Name1"},
             {id:124, value:"value2", name:"Name1"},
             {id:125, value:"value3", name:"Name2"},
             {id:126, value:"value4", name:"Name2"}
            ],
result = array.reduce((p,c) => p[c.name] ? p : (p[c.name] = true, p.push(c.name), p), []);
console.log(result);


이 ES5 솔루션은 성능이 좋지만 두 가지 목적으로 어레이를 사용하는 것은 혼란스럽고 이름 중 하나가 숫자 일 경우 위험합니다. p[c.name]별도의 개체에서 작업을 수행 o한 다음 나중에 폐기 하는 것이 좋습니다 .
joeytwiddle

7

name값만 필요하다면 a Set가 갈 길이 라는 데 동의합니다 .

그러나name 속성을 기반으로 고유 한 개체의 배열을 얻으려면 Map. 맵을 만드는 빠른 방법은 [key, value]배열 배열을 사용하는 것입니다.

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }],
      unique = new Map(array.map(obj => [obj.name, obj]));

// To get the unique objects
const uniques = Array.from(unique.values());

// Get the names like you already did:
console.log("Names:", uniques.map(obj => obj.name));

// If you ever need the complete array of unique objects, you got a ref:
console.log(JSON.stringify(uniques));
.as-console-wrapper { min-height: 100%; }

의 추가 이점은 소스 개체와의 연결을 끊지 않고 고유하지 않은 항목을 잘라내 Map는 두 filter기능을 모두 얻을 수 있다는 것 입니다. 물론 고유 한 개체 집합을 여러 번 참조해야하는 경우에만 필요합니다.



2

ES6를 사용하면이 작업을 수행 할 수 있습니다.

var array=[
    {id:123, value:"value1", name:"Name1"},
    {id:124, value:"value2", name:"Name1"},
    {id:125, value:"value3", name:"Name2"},
    {id:126, value:"value4", name:"Name2"}
];

var set = new Set();

array.forEach((a)=>{
    set.add(a.name);
}); 

console.log(Array.from(set));


11
map부작용이 아닌 순수한 기능과 함께 사용되어야합니다. 이것은 forEach또는에 대한 직업입니다 reduce.
Vincent van der Weele

1

UnderscoreJS 사용,

array = [{id:123, value:"value1", name:"Name1"}, {id:124, value:"value2", name:"Name1"}, {id:125, value:"value3", name:"Name2"}, {id:126, value:"value4", name:"Name2"}];
get_names =  _.pluck(_.uniq(array, 'name'), 'name')
console.log(get_names)
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

`


0

ES5에서는 O ( n ) 성능을 위한 사전으로 객체를 사용합니다 .

모든 키가 문자열 인 경우에만 작동합니다.

var array = [
    {id: 123, value: "value1", name: "Name1"},
    {id: 124, value: "value2", name: "Name1"},
    {id: 125, value: "value3", name: "Name2"},
    {id: 126, value: "value4", name: "Name2"}
];

var allNames = array.map(item => item.name);

var map = {};
allNames.forEach(name => {
  map[name] = true;
});
var uniqueNames = Object.keys(map);

console.log(uniqueNames);

원하는 경우 하나의 표현식에서 동일한 작업을 수행 할 수 있습니다.

var uniqueNames = Object.keys(allNames.reduce((m, n) => (m[n] = true, m), {}));

하지만 명령형이 더 읽기 쉽다는 것을 알았습니다.


명확성을 위해 ES6 화살표 기능을 사용했습니다. 트랜스 파일러없이 ES5를 실제로 대상으로하는 경우에는 대신 전체 양식을 사용해야합니다.function (item) { return item.name; }
joeytwiddle

에 대한 대안으로 Object.keys(), 이 답변filter()아직지도에 저장되지 않은 이름 만 유지하는 데 사용 되며 이는 매우 우아합니다.
joeytwiddle


0

아직 최대의 호환성 을 원한다면 간결한 구문을 사용하려면 다음 array#forEach()array#indexOf()같은 방법을 사용하십시오 .

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }]

// initialize an empty array named names
let names = [];

// iterate through every element of `array` & check if it's 'name' key's value already in names array if not ADD it 
array.forEach(function(element) { if (names.indexOf(element.name) === -1) names.push(element.name) });
// or use tilde like this:
//array.forEach(function(element) { if (~names.indexOf(element.name)) names.push(element.name) });

console.log(names);

그러나, 호환성이있는 경우는 문제에없는 사용은 6 ECMA 스크립트Set객체 array#mapArray.from()같은 방법 :

const array = [{ id: 123, value: "value1", name:"Name1" }, { id: 124, value: "value2", name: "Name1" }, { id: 125, value: "value3", name: "Name2" }, { id: 126, value: "value4", name: "Name2" }];

// iterate through every element from array using map and store it in Set(a Set won't have duplicates) then convert the Set back to Array(using Array.from)
let names = Array.from(new Set(array.map(element => element.name)));

console.log(names);


0

그것이 별도의 빈 배열을 사용하여 내가 한 방법입니다.

var array = [
   {id:123, value:"value1", name:"Name1"},
   {id:124, value:"value2", name:"Name1"},
   {id:125, value:"value3", name:"Name2"},
   {id:126, value:"value4", name:"Name2"}	    
];

var array2 = []		
		
for (i=0; i<array.length;i++){						
   if (array2.indexOf(array[i].name) == -1){				
     array2.push(array[i].name);
    }
}			

console.log(array2)	


-1

1 라이너를 찾는 분

const names = array.reduce((acc, {name}) => acc.includes(name) ? acc : [name, ...acc], []);

또는 배열의 프로토 타입에서 메서드를 사용하지 않고

const { reduce, includes } = Array;
const names = reduce(array, (acc, {name}) => includes(acc, name) ? acc : [name, ...acc], []);

이를 처리하기위한 일부 순수 함수를 작성하는 데 유용 할 수 있습니다.

const get_uniq_values = (key, arr) => reduce(arr, (a, o) => includes(a, o[key]) ? a : [o[key], ...a], []);

-1
var __array=[{id:123, value:"value1", name:"Name1"},{id:124, value:"value2", name:"Name1"},{id:125, value:"value3", name:"Name2"},{id:126, value:"value4", name:"Name2"}];

function __checkArray(__obj){
    var flag = true;
    for(let i=0; i < __array.length; i++){
        if(__obj.id == __array.id){
            flag = false;
            break;
        }
    }

    return flag;
}

var __valToPush = {id: 127, value: "value5", name: "Name3"};
if(__checkArray(__valToPush)){
    __array.push(__valToPush)
}

11
밑줄을 너무 많이 사용하는 특별한 이유가 있습니까?
Nina Scholz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.