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)
이것이 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);
}
ES6 / ES2015 이상을 사용하는 경우 다음과 같이 할 수 있습니다.
const unique = [...new Set(array.map(item => item.age))];
방법은 다음과 같습니다 .
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]
이와 같은 사전 접근 방식을 사용할 수 있습니다. 기본적으로 사전에서 키로 구별하려는 값을 지정합니다. 키가 존재하지 않으면 해당 값을 고유 한 값으로 추가하십시오.
var unique = {};
var distinct = [];
for( var i in array ){
if( typeof(unique[array[i].age]) == "undefined"){
distinct.push(array[i].age);
}
unique[array[i].age] = 0;
}
실제 데모는 다음과 같습니다. http://jsfiddle.net/jbUKP/1
이것은 O (n)입니다. 여기서 n은 배열의 객체 수이고 m은 고유 값의 수입니다. 각 값을 한 번 이상 검사해야하므로 O (n)보다 빠른 방법은 없습니다.
공연
http://jsperf.com/filter-versus-dictionary 이 사전을 실행할 때 30 % 더 빨랐습니다.
2017 년 8 월 25 일 현재 Typescript 용 ES6를 통한 새로운 세트를 사용하여이 문제를 해결하는 방법입니다.
Array.from(new Set(yourArray.map((item: any) => item.id)))
ES6 기능을 사용하면 다음과 같은 작업을 수행 할 수 있습니다.
const uniqueAges = [...new Set( array.map(obj => obj.age)) ];
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]
편집 : Aight! 성능면에서 가장 효율적인 방법은 아니지만 가장 읽기 쉬운 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))];
ES6 예
var 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
const unique = [...s]; // [17, 35] Use the spread operator to transform a set into an Array
// or
const unique2 = Array.from(s); // [17, 35]
forEach
(최신 브라우저 및 노드 JS 세계에 도움) @ 트래비스-J의 답변 버전 :
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]
이미 유효한 답변이 많이 있지만 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]
기본적으로 모든 새 프로젝트에서 Underscore 를 고수하기 시작 했기 때문에 이러한 작은 데이터 전송 문제에 대해 생각할 필요가 없습니다.
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]
합니다.
lodash를 사용하여
var array = [
{ "name": "Joe", "age": 17 },
{ "name": "Bob", "age": 17 },
{ "name": "Carl", "age": 35 }
];
_.chain(array).pluck('age').unique().value();
> [17, 35]
이 문제를 해결하는 또 다른 방법이 있습니다.
var result = {};
for(var i in array) {
result[array[i].age] = null;
}
result = Object.keys(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이 최적화에있어 최고의 역할을하는 것처럼 보입니다.
왜 위의 스 니펫이 다른 코드와 비교하여 그렇게 빠른지 잘 모르겠습니다. 어쩌면 나보다 현명한 사람이 대답 할 수 있습니다. ;-)
underscore.js _.uniq(_.pluck(array,"age"))
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;
}
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/
다음은 reduce를 사용하고 매핑을 허용하며 삽입 순서를 유지하는 다목적 솔루션입니다.
items : 배열
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);
이것을 배열 프로토 타입에 추가하고 스타일 인 경우 items 매개 변수를 생략 할 수 있습니다.
const distinctLastNames = items.distinct( (item)=>item.lastName) ) ;
const distinctItems = items.distinct() ;
배열 대신 Set을 사용하여 일치 속도를 높일 수도 있습니다.
function distinct(items, mapper) {
if (!mapper) mapper = (item)=>item;
return items.map(mapper).reduce((acc, item) => {
acc.add(item);
return acc;
}, new Set());
}
const x = [
{"id":"93","name":"CVAM_NGP_KW"},
{"id":"94","name":"CVAM_NGP_PB"},
{"id":"93","name":"CVAM_NGP_KW"},
{"id":"94","name":"CVAM_NGP_PB"}
].reduce(
(accumulator, current) => accumulator.some(x => x.id === current.id)? accumulator: [...accumulator, current ], []
)
console.log(x)
/* output
[
{ id: '93', name: 'CVAM_NGP_KW' },
{ id: '94', name: 'CVAM_NGP_PB' }
]
*/
방금 이것을 찾았고 유용하다고 생각했습니다.
_.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)})
Array.prototype.includes가 포함되어 있거나 polyfill 하려는 경우 다음 과 같이 작동합니다.
var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.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);```
나와 같은 속도를 유지하면서보다 "기능적인"기능을 선호하는 경우이 예에서는 축소 클로저 안에 래핑 된 빠른 사전 검색을 사용합니다.
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]
}
}, [{},[]])
이 테스트 에 따르면 내 솔루션은 제안 된 답변보다 두 배 빠릅니다.
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;
}
타이프 스크립트에 강력한 형식의 쿼리 가능한 컬렉션 을 제공하는 라이브러리가 있습니다 .
컬렉션은 다음과 같습니다
- 명부
- 사전
라이브러리를 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;
}
}
새로운 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에서 내 게시물 을 확인하십시오 .
단지 시도
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);
뛰어난 성능의 단순한 원 라이너. 내 테스트 에서 ES6 솔루션보다 6 % 빠릅니다 .
var ages = array.map (function (o) {return o.age}). filter (function (v, i, a) {return a.indexOf (v) === i});
나는 이것이 오래되고 상대적으로 잘 대답 된 질문이라는 것을 알고 있으며 내가주는 대답은 완전한 대상을 되 찾을 것입니다 (이 게시물에 대한 많은 의견에서 제안 된 것으로 보임). "끈적"일 수도 있지만 가독성 측면에서 다른 많은 솔루션보다 훨씬 깨끗합니다 (효율적이지는 않지만).
이것은 배열 내부의 완전한 객체의 고유 한 배열을 반환합니다.
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))```
나는 Kotlin에서와 같은 일반적인 경우를 위해 TypeScript에서 내 자신을 썼습니다 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 가 필요할 수 있습니다.
'Programing' 카테고리의 다른 글
DateTime을 VarChar로 변환하는 방법 (0) | 2020.03.18 |
---|---|
게터와 세터를 사용하는 파이썬적인 방법은 무엇입니까? (0) | 2020.03.18 |
ASP.NET의 숨겨진 기능 (0) | 2020.03.18 |
JavaScript 가비지 수집이란 무엇입니까? (0) | 2020.03.18 |
Google reCAPTCHA v2는 뒤에서 어떻게 작동합니까? (0) | 2020.03.18 |