Jak uzyskać różne wartości z tablicy obiektów w JavaScript?


383

Zakładając, że mam następujące:

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

Jaki jest najlepszy sposób, aby uzyskać tablicę wszystkich różnych grup wiekowych, tak aby uzyskać tablicę wyników:

[17, 35]

Czy jest jakiś sposób, w jaki mógłbym alternatywnie skonstruować dane lub lepszą metodę, tak że nie musiałbym iterować przez każdą tablicę sprawdzając wartość „age” i sprawdzać, czy istnieje inna tablica, i czy ją dodać, jeśli nie?

Gdyby istniał jakiś sposób, mogłem wyciągnąć różne epoki bez iteracji ...

Obecny nieefektywny sposób chciałbym poprawić ... Jeśli to znaczy, że zamiast „tablicy” jest tablicą obiektów, ale „mapą” obiektów z jakimś unikalnym kluczem (tj. „1,2,3”), która byłaby też dobrze. Po prostu szukam najbardziej wydajnego sposobu.

Oto jak obecnie to robię, ale dla mnie iteracja wydaje się po prostu kiepska dla wydajności, nawet jeśli działa ...

var distinct = []
for (var i = 0; i < array.length; i++)
   if (array[i].age not in distinct)
      distinct.push(array[i].age)

34
iteracja nie jest „kiepska dla wydajności” i nie można nic zrobić z każdym elementem „bez iteracji”. możesz użyć różnych funkcjonalnie wyglądających metod, ale ostatecznie coś na pewnym poziomie musi się powtarzać nad przedmiotami.
Eevee

// 100% działającego kodu const listOfTags = [{id: 1, label: „Hello”, kolor: „red”, sortowanie: 0}, {id: 2, label: „World”, kolor: „green”, sortowanie : 1}, {id: 3, etykieta: „Witaj”, kolor: „niebieski”, sortowanie: 4}, {id: 4, etykieta: „Słońce”, kolor: „żółty”, sortowanie: 5}, {id : 5, etykieta: „Cześć”, kolor: „czerwony”, sortowanie: 6}], klucze = [„etykieta”, „kolor”], filtrowane = listOfTags.filter ((s => o => (k => ! s.has (k) && s.add (k)) (keys.map (k => o [k]). join ('|'))) (new Set)); console.log (filtrowane);
Sandeep Mishra

1
laska jest świetna, ale pytanie z podanych danych i odpowiedź jest już odpowiedział tutaj: stackoverflow.com/questions/53542882/... . jaki jest cel nagrody? czy powinienem rozwiązać ten konkretny problem za pomocą dwóch lub więcej kluczy?
Nina Scholz

Setprzedmioty mapsą marnotrawstwem. Ta praca zajmuje tylko prosty .reduce()etap.
Redu,

Odpowiedzi:


126

Gdyby to był PHP, zbudowałbym tablicę z kluczami i zabrałbym array_keysna koniec, ale JS nie ma takiego luksusu. Zamiast tego spróbuj tego:

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

15
Nie, ponieważ array_uniqueporównałby cały przedmiot, a nie tylko wiek, o jaki tu proszono.
Niet the Dark Absol

6
Myślę, że flags = {}jest lepszy niżflags = []
zhuguowei

3
@zhuguowei, być może, chociaż nie ma nic złego w rzadkich tablicach - i założyłem, że agejest to względnie mała liczba całkowita (na pewno <120)
Niet the Dark Absol

jak moglibyśmy wydrukować całkowitą liczbę osób w tym samym wieku?
user1788736,

605

Jeśli używasz ES6 / ES2015 lub nowszej wersji, możesz to zrobić w ten sposób:

const unique = [...new Set(array.map(item => item.age))];

Oto przykład, jak to zrobić.


11
TypeError: (intermediate value).slice is not a function
Pojawia

7
@ Thomas ... oznacza operatora rozprzestrzeniania. W tym przypadku oznacza to utworzenie nowego zestawu i rozłożenie go na liście. Więcej informacji na ten temat można znaleźć tutaj: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Vlad Bezden

10
dla maszynopisu musisz użyć nowego zestawu zawiniętego w Array.from () ... Podam tę odpowiedź poniżej. @AngJobs
Christian Matthew

4
czy można znaleźć unikalne obiekty na podstawie wielu kluczy w obiekcie?
Jefree Sujit

13
To rozwiązanie zostało prawie dosłownie kilka miesięcy wcześniej @Russell Vea. Czy sprawdziłeś istniejące odpowiedzi? Ale z drugiej strony ponad 266 głosów pokazuje, że nikt inny też tego nie sprawdził.
Dan Dascalescu

164

za pomocą 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]

2
Jeśli chcę uzyskać wartość z jej indeksem, to jak mogę uzyskać Przykład: Chcę uzyskać {„name”: „Bob”, „age”: „17”}, {„name”: „Bob”, „age „:„ 17 ”}
Abdullah Al Mamun

10
Dlatego musisz ciągle przewijać
Alejandro Bastidas

5
@AbdullahAlMamun możesz najpierw użyć mapy w .filter zamiast wywoływać .map w następujący sposób:array.filter((value, index, self) => self.map(x => x.age).indexOf(value.age) == index)
Leo

1
ps: .map wewnątrz .filter może być powolny, więc bądź ostrożny z dużymi tablicami
Leo

2
@IvanNosov twój fragment jest bardzo dobry, chociaż kilka linii objaśnienia, w jaki sposób działa ze wskaźnikami do mapowania i filtrowania dokumentacji, sprawi, że będzie on idealny i przejrzysty dla początkujących
azakgaim

128

Możesz użyć takiego słownika. Zasadniczo przypisujesz wartość, którą chcesz odróżniać, jako klucz w „słowniku” (tutaj używamy tablicy jako obiektu, aby uniknąć trybu słownikowego). Jeśli klucz nie istnieje, dodajesz tę wartość jako odrębną wartość.

Oto działające demo:

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>

Będzie to O (n), gdzie n to liczba obiektów w tablicy, a m to liczba unikalnych wartości. Nie ma szybszego sposobu niż O (n), ponieważ musisz sprawdzić każdą wartość przynajmniej raz.

Poprzednia wersja tego używała obiektu i dla in. Miały one niewielki charakter i od tego czasu zostały nieznacznie zaktualizowane powyżej. Jednak przyczyną pozornej poprawy wydajności między dwiema wersjami oryginalnego jsperf był tak mały rozmiar próbki danych. Tak więc głównym porównaniem w poprzedniej wersji była różnica między wewnętrzną mapą a użyciem filtra w porównaniu do wyszukiwania w trybie słownikowym.

Zaktualizowałem powyższy kod, jak zauważyłem, ale zaktualizowałem również jsperf, aby przeglądał 1000 obiektów zamiast 3. 3 przeoczył wiele pułapek związanych z wydajnością ( przestarzały jsperf ).

Wydajność

https://jsperf.com/filter-vs-dictionary-more-data Kiedy uruchomiłem ten słownik, był o 96% szybszy.

filtr vs słownik


4
szybki i bez żadnych dodatkowych wtyczek. Naprawdę fajnie
mihai

2
co powiesz naif( typeof(unique[array[i].age]) == "undefined"){ distinct.push(array[i].age); unique[array[i].age] = 0; }
Timeless

7
Wow, wydajność naprawdę się zmieniła na korzyść opcji mapy. Kliknij ten link jsperf!
AT

1
@ 98percentmonkey - Obiekt został użyty w celu ułatwienia „podejścia słownikowego”. Wewnątrz obiektu każde śledzone wystąpienie jest dodawane jako klucz (lub pojemnik). W ten sposób, gdy napotkamy jakieś zdarzenie, możemy sprawdzić, czy klucz (lub bin) istnieje; jeśli istnieje, wiemy, że wystąpienie nie jest unikalne - jeśli nie istnieje, wiemy, że wystąpienie jest unikalne i dodaj je.
Travis J

1
@ 98percentmonkey - Powodem użycia obiektu jest to, że wyszukiwanie to O (1), ponieważ raz sprawdza nazwę właściwości, podczas gdy tablica to O (n), ponieważ musi sprawdzać każdą wartość, aby sprawdzić istnienie. Pod koniec procesu zestaw kluczy (pojemników) w obiekcie reprezentuje zestaw unikalnych wystąpień.
Travis J

91

W ten sposób rozwiązujesz ten problem za pomocą nowego zestawu za pomocą ES6 for Typescript od 25 sierpnia 2017 r

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

3
to pomogło, było przed podziękowaniami. Typ „Set” nie jest typem tablicowym
Robert King

1
To świetna odpowiedź. Do czasu przewinięcia do tego, miałem zamiar napisać odpowiedź: Object.keys (values.reduce <any> ((x, y) => {x [y] = null; return x;}, {} )); Ale ta odpowiedź jest bardziej zwięzła i dotyczy wszystkich typów danych zamiast tylko ciągów.
jgosar

1
ta odpowiedź jest spektakularna!
lukeocodes

78

Korzystając z funkcji ES6, możesz zrobić coś takiego:

const uniqueAges = [...new Set( array.map(obj => obj.age)) ];

6
To podejście będzie działać tylko na typach pierwotnych (tak jest tutaj, ponieważ wiek to tablica liczb), ale nie powiedzie się dla obiektów.
k0pernikus

jakiś pomysł, jak to zrobić dla obiektów z dwoma kluczami?
cegprakash

1
Coś w styluconst uniqueObjects = [ ...new Set( array.map( obj => obj.age) ) ].map( age=> { return array.find(obj => obj.age === age) } )
Harley B,

62

Chciałbym po prostu zmapować i usunąć duplikaty:

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]

Edycja: Aight! Nie najskuteczniejszy sposób pod względem wydajności, ale najprostszy i najbardziej czytelny IMO. Jeśli naprawdę zależy Ci na mikrooptymalizacji lub masz ogromne ilości danych, regularna forpętla będzie bardziej „wydajna”.


3
@elclanrs - „najbardziej wydajny sposób wydajności” - To podejście jest powolne .
Travis J

1
@Eevee: Rozumiem. Wersja podkreślenia w twojej odpowiedzi też nie jest bardzo szybka , to znaczy w końcu wybierasz to, co jest wygodniejsze, wątpię, czy 1-30% mniej więcej odzwierciedla „ogromną poprawę” w testach ogólnych i kiedy OP / s są w tysiącach .
elclanrs

4
Cóż, pewnie. mając tylko trzy elementy , najszybszą rzeczą jest utworzenie trzech zmiennych i użycie niektórych ifs. uzyskasz bardzo różne wyniki z trzema milionami.
Eevee

1
nie szybko, ale w moim przypadku załatwiło sprawę, ponieważ nie mam do czynienia z dużym zbiorem danych, dzięki.
Felipe Alarcon

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

Przykład 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]

6
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, jak i dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi.
Alexander

Pierwszy, który używa indexOf vs. index jest po prostu genialny.
niestety

Zauważ, że działa to tylko dla prymitywnych wartości. Jeśli masz szereg dat, potrzebujesz bardziej niestandardowych metod. Przeczytaj więcej tutaj: codeburst.io/javascript-array-distinct-5edc93501dc4
Molx

36

Dla tych, którzy chcą zwrócić obiekt o wszystkich właściwościach unikatowych według klucza

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.


2
Uwaga: spowoduje to wybranie ostatniego zduplikowanego elementu z listy.
Eugene Kulabuhov

1
Dodając to do odpowiedzi!
Arun Kumar Saini

1
Dokładnie tego szukałem. Wielkie dzięki za udostępnienie!
Devner

1
Szczerze mówiąc, myślę, że powinna to być NAJLEPSZA odpowiedź!
Jaroslav Benc

26

Istnieje już wiele prawidłowych odpowiedzi, ale chciałem dodać tę, która używa tylko reduce()metody, ponieważ jest czysta i prosta.

function uniqueBy(arr, prop){
  return arr.reduce((a, d) => {
    if (!a.includes(d[prop])) { a.push(d[prop]); }
    return a;
  }, []);
}

Użyj tego w ten sposób:

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

var ages = uniqueBy(array, "age");
console.log(ages); // [17, 35]

20

forEachWersja odpowiedzi @ Travis-j jest (pomocny w nowoczesnych przeglądarkach, a węzeł JS świata):

var unique = {};
var distinct = [];
array.forEach(function (x) {
  if (!unique[x.age]) {
    distinct.push(x.age);
    unique[x.age] = true;
  }
});

34% szybszy na Chrome v29.0.1547: http://jsperf.com/filter-versus-dictionary/3

I ogólne rozwiązanie, które przyjmuje funkcję mapowania (nieco wolniej niż bezpośrednia mapa, ale jest to oczekiwane):

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]

1
Najbardziej podoba mi się ogólne rozwiązanie, ponieważ jest mało prawdopodobne, aby wiek był jedyną wyraźną wartością potrzebną w scenariuszu z prawdziwego świata.
Toft,

5
W ogólności zmień „odrębny.push (klucz)” na „odrębny.push (x)”, aby zwrócić listę rzeczywistych elementów, które moim zdaniem są bardzo użyteczne!
Silas Hansen

15

Domyślnie zacząłem umieszczać podkreślenie we wszystkich nowych projektach, aby nigdy nie musiałem myśleć o tych małych problemach z mungingiem danych.

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

Produkuje [17, 35].


13

Oto inny sposób na rozwiązanie tego:

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

Nie mam pojęcia, jak szybko to rozwiązanie jest porównywane z innymi, ale podoba mi się czystszy wygląd. ;-)


EDYCJA: OK, powyższe wydaje się być najwolniejszym rozwiązaniem ze wszystkich tutaj.

Stworzyłem tutaj test wydajności: http://jsperf.com/distinct-values-from-array

Zamiast testować dla grup wiekowych (liczby całkowite), postanowiłem porównać nazwy (ciągi znaków).

Metoda 1 (rozwiązanie TS) jest bardzo szybka. Co ciekawe, metoda 7 przewyższa wszystkie inne rozwiązania, tutaj właśnie pozbyłem się .indexOf () i użyłem jej „ręcznej” implementacji, unikając wywoływania zapętlonych funkcji:

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

Różnica w wydajności w Safari i Firefox jest niesamowita i wygląda na to, że Chrome najlepiej radzi sobie z optymalizacją.

Nie jestem do końca pewien, dlaczego powyższe fragmenty są tak szybkie w porównaniu do innych, może ktoś mądrzejszy ode mnie ma odpowiedź. ;-)


9

za pomocą lodash

var array = [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
];
_.chain(array).pluck('age').unique().value();
> [17, 35]

2
Czy możesz wyjaśnić, jak to zrobić za pomocą zwykłego javascript, jak sugeruje to pytanie?
Ruskin

jest to funkcja podkreślenia _.chain
vini

2
ale pluck () nie jest w lodash.
Yash Vekaria

1
_.chain (array) .map ('age'). unique (). value (); pracował dla mnie.
Yash Vekaria

w wersji 4.0 wprowadzono kilka przełomowych zmian - stackoverflow.com/a/31740263/4050261
Adarsh ​​Madrecha

7

Korzystanie z Lodash

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

_.chain(array).map('age').unique().value();

Zwraca [17,3]


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


5

Oto wszechstronne rozwiązanie, które wykorzystuje redukcję, pozwala na mapowanie i utrzymuje kolejność wstawiania.

items : Tablica

mapper : Unary funkcja, która mapuje element do kryteriów lub pusta, aby mapować sam element.

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;
    }, []);
}

Stosowanie

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

Możesz dodać to do prototypu Array i pominąć parametr items , jeśli taki jest twój styl ...

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

Możesz także użyć zestawu zamiast tablicy, aby przyspieszyć dopasowanie.

function distinct(items, mapper) {
    if (!mapper) mapper = (item)=>item;
    return items.map(mapper).reduce((acc, item) => {
        acc.add(item);
        return acc;
    }, new Set());
}

5

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' } 
]
*/


2
to wygląda jak O (n ^ 2)
cegprakash

4

Właśnie to znalazłem i pomyślałem, że jest to przydatne

_.map(_.indexBy(records, '_id'), function(obj){return obj})

Ponownie użyj podkreślenia , więc jeśli masz taki obiekt

var records = [{_id:1,name:'one', _id:2,name:'two', _id:1,name:'one'}]

da ci tylko unikalne przedmioty.

To, co się tutaj dzieje, polega na indexByzwróceniu takiej mapy

{ 1:{_id:1,name:'one'}, 2:{_id:2,name:'two'} }

i tylko dlatego, że jest to mapa, wszystkie klucze są unikalne.

Następnie mapuję tę listę z powrotem do tablicy.

W przypadku, gdy potrzebujesz tylko odrębnych wartości

_.map(_.indexBy(records, '_id'), function(obj,key){return key})

Pamiętaj, że keyjest zwracany jako ciąg, więc jeśli potrzebujesz liczb całkowitych, powinieneś to zrobić

_.map(_.indexBy(records, '_id'), function(obj,key){return parseInt(key)})

4

myślę, że szukasz funkcji groupBy (za pomocą Lodash)

_personsList = [{"name":"Joe", "age":17}, 
                {"name":"Bob", "age":17}, 
                {"name":"Carl", "age": 35}];
_uniqAgeList = _.groupBy(_personsList,"age");
_uniqAges = Object.keys(_uniqAgeList);

daje wynik:

17,35

Wersja demonstracyjna jsFiddle: http://jsfiddle.net/4J2SX/201/


3

Jeśli tak jak ja wolisz bardziej „funkcjonalny” bez uszczerbku dla szybkości, w tym przykładzie zastosowano szybkie wyszukiwanie słownika w celu zmniejszenia zamknięcia.

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]
    }
}, [{},[]])

Według tego testu moje rozwiązanie jest dwa razy szybsze niż proponowana odpowiedź


3
[...new Set([
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
  ].map(({ age }) => age))]

3

Wiem, że mój kod ma małą długość i złożoność czasu, ale jest zrozumiały, więc spróbowałem w ten sposób.

Próbuję tu opracować funkcję opartą na prototypie, a kod również się zmienia.

Tutaj Distinct to moja własna funkcja prototypowa.

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

  Array.prototype.Distinct = () => {
    var output = [];
    for (let i = 0; i < array.length; i++) {
      let flag = true;
      for (let j = 0; j < output.length; j++) {
        if (array[i].age == output[j]) {
          flag = false;
          break;
        }
      }
      if (flag)
        output.push(array[i].age);
    }
    return output;
  }
  //Distinct is my own function
  console.log(array.Distinct());
</script>


2

Jeśli masz plik Array.prototype.includes lub chcesz go wypełnić , działa to:

var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.age); });

1

Mój poniższy kod pokaże unikalną tablicę wiekową, a także nową tablicę bez zduplikowanego wieku

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

1

Napisałem własną w TypeScript, na ogólny przypadek, taki jak ten w Kotlinie 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)));
}

UOczywiście gdzie jest haszowanie. W przypadku obiektów może być konieczne https://www.npmjs.com/package/es6-json-stable-stringify


1

W przypadku, gdy potrzebujesz unikalnego całego obiektu

const _ = require('lodash');

var objects = [
  { 'x': 1, 'y': 2 },
  { 'y': 1, 'x': 2 },
  { 'x': 2, 'y': 1 },
  { 'x': 1, 'y': 2 }
];

_.uniqWith(objects, _.isEqual);

[Obiekt {x: 1, y: 2}, Obiekt {x: 2, y: 1}]


downvoter: Umysł wyjaśnienia, dlaczego downvote?
cegprakash

1

Odpowiedź na to stare pytanie jest bezcelowa, ale istnieje prosta odpowiedź, która mówi o naturze Javascript. Obiekty w JavaScript są z natury tablicami mieszającymi. Możemy użyć tego, aby uzyskać skrót unikalnych kluczy:

var o = {}; array.map(function(v){ o[v.age] = 1; });

Następnie możemy zredukować skrót do tablicy unikalnych wartości:

var a2 = []; for (k in o){ a2.push(k); }

To wszystko czego potrzebujesz. Tablica a2 zawiera tylko unikalne epoki.


1

Prosty jednowarstwowy z doskonałą wydajnością. 6% szybciej niż rozwiązania ES6 w moich testach .

var ages = array.map(function(o){return o.age}).filter(function(v,i,a) {
    return a.indexOf(v)===i
});

@ Jeb50 Chcesz dodać wieloliniowy, łatwy do odczytania? Patrząc na innych tutaj, naprawdę nie czuję, że są łatwe do odczytania lub zrozumienia. Myślę, że najlepiej umieścić to w funkcji, która opisuje, co robi.
Craig

2
Dzięki funkcji strzałek: array.map( o => o.age).filter( (v,i,a) => a.indexOf(v)===i). Używam słowa kluczowego function tak rzadko teraz, że muszę czytać rzeczy dwa razy, gdy widzę go 😊
Drenajów
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.