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)
Rolando
źródło
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);
}
Niet the Dark Absol
źródło
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ć.

Vlad Bezden
źródło
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]
Ivan Nosov
źródło
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

Travis J
źródło
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)))
Christian Matthew
źródło
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)) ];
Russell Vea
źródło
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”.

elclanrs
źródło
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]
oleg gabureak
źródło
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.

Arun Kumar Saini
źródło
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]
Harry Stevens
źródło
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]
Mrchief
źródło
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].

Eevee
źródło
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ź. ;-)

BaM
źródło
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]
Ivan Nosov
źródło
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]

Yash Vekaria
źródło
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;
}
Dmitriy Kupriyanov
źródło
5

underscore.js _.uniq(_.pluck(array,"age"))

Radosław Kopczyński
źródło
5
Dodaj wyjaśnienie, w jaki sposób odpowiada to pytanie.
Robotic Cat
2
_.pluck został usunięty na rzecz _.map
Ajax3.14
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());
}
Steven Spungin
źródło
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' } 
]
*/

Ruben Morales Felix
źródło
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)})
simo
źródło
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/

Amil Sajeev
źródło
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ź

bmaggi
źródło
3
[...new Set([
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
  ].map(({ age }) => age))]
Marian Zburlea
źródło
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>

Prabhat
źródło
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); });
quillbreaker
źródło
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);```
Shridhar Sagari
źródło
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

Polv
źródło
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}]

cegprakash
źródło
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.

Preston L. Bannister
źródło
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
});
Craig
źródło
@ 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