Làm cách nào để có được các giá trị khác biệt từ một mảng các đối tượng trong JavaScript?


384

Giả sử tôi có những điều sau đây:

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

Cách tốt nhất để có thể có được một mảng của tất cả các độ tuổi khác nhau là gì để tôi có được một mảng kết quả:

[17, 35]

Có cách nào đó tôi có thể thay thế cấu trúc dữ liệu hoặc phương pháp tốt hơn để tôi không phải lặp lại qua từng mảng kiểm tra giá trị của "tuổi" và kiểm tra xem có tồn tại mảng khác không và thêm vào nếu không?

Nếu có cách nào đó tôi có thể rút ra những thời đại khác biệt mà không cần lặp lại ...

Cách không hiệu quả hiện tại tôi muốn cải thiện ... Nếu điều đó có nghĩa là thay vì "mảng" là một mảng các đối tượng, nhưng một "bản đồ" của các đối tượng với một khóa duy nhất (ví dụ "1,2,3") sẽ là cũng được Tôi chỉ tìm kiếm cách hiệu quả nhất.

Sau đây là cách tôi hiện đang làm, nhưng đối với tôi, việc lặp đi lặp lại dường như chỉ là hiệu quả cho dù nó hoạt động ...

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

34
Lặp đi lặp lại không phải là "khủng hoảng cho hiệu quả" và bạn không thể làm bất cứ điều gì cho mọi yếu tố "mà không lặp lại". bạn có thể sử dụng các phương pháp tìm kiếm chức năng khác nhau, nhưng cuối cùng, một số thứ ở một mức độ nào đó phải lặp đi lặp lại trên các mục.
Eevee

// 100% mã chạy const listOfTags = [{id: 1, nhãn: "Hello", color: "red", sorting: 0}, {id: 2, nhãn: "World", color: "green", sorting : 1}, {id: 3, nhãn: "Xin chào", màu: "xanh", sắp xếp: 4}, {id: 4, nhãn: "Ánh nắng mặt trời", màu: "vàng", sắp xếp: 5}, {id : 5, nhãn: "Xin chào", màu: "đỏ", sắp xếp: 6}], phím = ['nhãn', 'màu'], được lọc = listOfTags.filter ((s => o => (k => ! s.has (k) && s.add (k)) (key.map (k => o [k]). tham gia ('|'))) (Bộ mới)); console.log (đã lọc);
Sandeep Mishra

1
tiền thưởng là rất tốt, nhưng câu hỏi với dữ liệu và câu trả lời đã cho đã được trả lời ở đây: stackoverflow.com/questions/53542882/ . mục đích của tiền thưởng là gì? Tôi nên trả lời vấn đề đặc biệt này với hai hoặc nhiều khóa?
Nina Scholz

Setđối tượng và maps là lãng phí. Công việc này chỉ cần một .reduce()giai đoạn đơn giản .
Redu

Câu trả lời:


126

Nếu đây là PHP tôi sẽ xây dựng một mảng với các khóa và lấy array_keysở cuối, nhưng JS không có sự xa xỉ như vậy. Thay vào đó, hãy thử điều này:

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
Không, bởi vì array_uniquesẽ so sánh toàn bộ mặt hàng, không chỉ độ tuổi như được hỏi ở đây.
Niet the Dark Tuyệt đối

6
Tôi nghĩ flags = {}là tốt hơnflags = []
zhuguowei

3
@zhuguowei có lẽ, mặc dù không có gì thực sự sai với các mảng thưa thớt - và tôi cũng cho rằng đó agelà một số nguyên tương đối nhỏ (<120 chắc chắn)
Niet the Dark Tuyệt đối

Làm thế nào chúng ta cũng có thể in ra tổng số người cùng tuổi?
dùng1788736

606

Nếu bạn đang sử dụng ES6 / ES2015 trở lên, bạn có thể thực hiện theo cách này:

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

Dưới đây là một ví dụ về cách làm điều đó.


11
Tôi gặp lỗi:TypeError: (intermediate value).slice is not a function
AngJobs trên Github

7
@Thomas ... có nghĩa là toán tử lây lan. Trong trường hợp này, điều đó có nghĩa là tạo tập hợp mới và trải rộng nó trong một danh sách. Bạn có thể tìm hiểu thêm về nó ở đây: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
trộm

10
đối với bản thảo, bạn phải sử dụng Set mới được gói trong Array.from () ... tôi sẽ cung cấp câu trả lời dưới đây. @AngJobs
Christian Matthew

4
có thể tìm ra các đối tượng duy nhất dựa trên nhiều khóa trong đối tượng không?
Jefree Sujit

14
Giải pháp này đã được đưa ra gần như nguyên văn một vài tháng trước đó bởi @Russell Vea. Bạn đã kiểm tra câu trả lời hiện có chưa? Nhưng sau đó, một lần nữa, hơn 266 phiếu bầu cho thấy không ai khác kiểm tra cả.
Dan Dascalescu

164

sử dụng 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
Nếu tôi muốn nhận giá trị với chỉ số của nó thì làm sao tôi có thể lấy Ví dụ: Tôi muốn nhận {"name": "Bob", "age": "17"}, {"name": "Bob", "age ":" 17 "}
Abdullah Al Mamun

10
Đó là lý do tại sao bạn phải tiếp tục di chuyển
Alejandro Bastidas

5
@AbdullahAlMamun bạn có thể sử dụng bản đồ trong .filter thay vì gọi .map trước, như thế này:array.filter((value, index, self) => self.map(x => x.age).indexOf(value.age) == index)
Leo

1
ps: .map bên trong .filter có thể chậm, vì vậy hãy cẩn thận với các mảng lớn
Leo

2
@IvanNosov đoạn trích của bạn rất tốt mặc dù một số dòng giải thích cách nó hoạt động với con trỏ để ánh xạ và tài liệu bộ lọc sẽ làm cho nó hoàn hảo và rõ ràng cho người mới bắt đầu
azakgaim

128

Bạn có thể sử dụng một cách tiếp cận từ điển như thế này. Về cơ bản, bạn chỉ định giá trị bạn muốn là khác biệt như một khóa trong "từ điển" (ở đây chúng tôi sử dụng một mảng làm đối tượng để tránh chế độ từ điển). Nếu khóa không tồn tại thì bạn thêm giá trị đó là khác biệt.

Đây là một bản demo làm việc:

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>

Đây sẽ là O (n) trong đó n là số lượng đối tượng trong mảng và m là số lượng giá trị duy nhất. Không có cách nào nhanh hơn O (n) vì bạn phải kiểm tra từng giá trị ít nhất một lần.

Phiên bản trước của điều này đã sử dụng một đối tượng và trong. Đây là những bản chất nhỏ và đã được cập nhật nhỏ ở trên. Tuy nhiên, lý do cho sự tiến bộ về hiệu suất giữa hai phiên bản trong jsperf ban đầu là do kích thước mẫu dữ liệu quá nhỏ. Do đó, so sánh chính trong phiên bản trước đã xem xét sự khác biệt giữa bản đồ nội bộ và sử dụng bộ lọc so với tra cứu chế độ từ điển.

Tôi đã cập nhật mã ở trên, như đã lưu ý, tuy nhiên, tôi cũng đã cập nhật jsperf để xem qua 1000 đối tượng thay vì 3. 3 bỏ qua nhiều cạm bẫy hiệu suất liên quan ( jsperf lỗi thời ).

Hiệu suất

https://jsperf.com/filter-vs-dipedia-more-data Khi tôi chạy từ điển này nhanh hơn 96%.

bộ lọc so với từ điển


4
nhanh chóng và không cần bất kỳ plugin bổ sung nào. Thật tuyệt
mihai

2
làm thế nào vềif( typeof(unique[array[i].age]) == "undefined"){ distinct.push(array[i].age); unique[array[i].age] = 0; }
vượt thời gian

7
Wow hiệu suất đã thực sự thay đổi theo hướng có lợi cho tùy chọn bản đồ. Nhấp vào liên kết jsperf!
TẠI

1
@ 98percentmonkey - Đối tượng được sử dụng để tạo điều kiện cho "cách tiếp cận từ điển". Bên trong đối tượng, mỗi lần xuất hiện được theo dõi sẽ được thêm dưới dạng khóa (hoặc thùng). Bằng cách này, khi chúng tôi gặp sự cố, chúng tôi có thể kiểm tra xem khóa (hoặc thùng) có tồn tại không; nếu nó tồn tại, chúng ta biết rằng sự xuất hiện không phải là duy nhất - nếu nó không tồn tại, chúng ta biết rằng sự xuất hiện là duy nhất và thêm nó vào.
Travis J

1
@ 98percentmonkey - Lý do sử dụng một đối tượng là tra cứu là O (1) vì nó kiểm tra tên thuộc tính một lần, trong khi đó một mảng là O (n) vì nó phải xem xét mọi giá trị để kiểm tra sự tồn tại. Khi kết thúc quá trình, tập hợp các khóa (thùng) trong đối tượng đại diện cho tập hợp các lần xuất hiện duy nhất.
Travis J

91

Đây là cách bạn sẽ giải quyết vấn đề này bằng cách sử dụng Bộ mới thông qua ES6 cho Bản in vào ngày 25 tháng 8 năm 2017

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

3
Điều này đã giúp, đã nhận được trước khi cảm ơn. Loại 'Set' không phải là kiểu mảng
vua robert

1
Đây là một câu trả lời tuyệt vời. Cho đến khi tôi cuộn xuống cái này, tôi sẽ viết một câu trả lời rằng: Object.keys (value.reduce <any> ((x, y) => {x [y] = null; return x;}, {} )); Nhưng câu trả lời này ngắn gọn hơn và áp dụng cho tất cả các loại dữ liệu thay vì chỉ các chuỗi.
jgosar

1
Câu trả lời này thật ngoạn mục!
lukeocodes

79

Sử dụng các tính năng ES6, bạn có thể làm một cái gì đó như:

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

6
Cách tiếp cận này sẽ chỉ hoạt động trên các kiểu nguyên thủy (đó là trường hợp ở đây vì tuổi là một mảng số) nhưng sẽ thất bại cho các đối tượng.
k0pernikus

Bất kỳ ý tưởng làm thế nào để làm cho nó hoạt động cho các đối tượng với hai phím?
cegprakash

1
Một cái gì đó giống nhưconst uniqueObjects = [ ...new Set( array.map( obj => obj.age) ) ].map( age=> { return array.find(obj => obj.age === age) } )
Harley B

62

Tôi chỉ cần lập bản đồ và xóa 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]

Chỉnh sửa: Aight! Không phải là cách hiệu quả nhất về hiệu suất, nhưng IMO đơn giản nhất dễ đọc nhất. Nếu bạn thực sự quan tâm đến tối ưu hóa vi mô hoặc bạn có lượng dữ liệu khổng lồ thì một forvòng lặp thông thường sẽ "hiệu quả" hơn.


3
@elclanrs - "cách hiệu quả nhất" - Cách tiếp cận này chậm .
Travis J

1
@Eevee: Tôi hiểu rồi. Phiên bản gạch dưới trong câu trả lời của bạn cũng không nhanh lắm , ý tôi là, cuối cùng bạn chọn những gì thuận tiện hơn, tôi nghi ngờ ít nhiều 1-30% phản ánh "sự cải thiện lớn" trong các thử nghiệm chung và khi OP / s có hàng ngàn .
elclanrs

4
tốt, chắc chắn chỉ với ba yếu tố , điều nhanh nhất là tạo ba biến và sử dụng một số ifs. bạn sẽ nhận được một số kết quả rất khác nhau với ba triệu.
Eevee

1
không nhanh nhưng trong trường hợp của tôi, nó đã làm được điều đó vì tôi không xử lý một tập dữ liệu lớn, cảm ơn.
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'));

Ví dụ 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
Mặc dù mã này có thể trả lời câu hỏi, việc cung cấp ngữ cảnh bổ sung về cách thứclý do giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Alexander

Cái đầu tiên sử dụng indexOf so với chỉ số thật tuyệt vời.
than ôi

Lưu ý rằng điều này chỉ hoạt động cho các giá trị nguyên thủy. Nếu bạn có một mảng ngày, thì bạn cần một số phương thức tùy chỉnh hơn. Đọc thêm tại đây: codeburst.io/javascript-array-distinc-5edc93501dc4
Molx

36

Đối với những người muốn trả về đối tượng với tất cả các thuộc tính duy nhất theo khóa

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
Lưu ý: điều này sẽ chọn mục trùng lặp cuối cùng trong danh sách.
Eugene Kulabuhov

1
Thêm điều này vào câu trả lời!
Arun Kumar Saini

1
Chính xác những gì tôi đang tìm kiếm. Cảm ơn rất nhiều vì đã chia sẻ!
Devner

1
Tôi nghĩ rằng đây phải là câu trả lời hàng đầu để thành thật!
Jaroslav Benc

26

Đã có nhiều câu trả lời hợp lệ, nhưng tôi muốn thêm một câu trả lời chỉ sử dụng reduce()phương pháp vì nó sạch và đơn giản.

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

Sử dụng nó như thế này:

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

Các forEachphiên bản của câu trả lời @ travis-j của (hữu ích trên các trình duyệt hiện đại và thế giới Node JS):

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

Nhanh hơn 34% trên Chrome v29.0.1547: http://jsperf.com/filter-versus-dipedia/3

Và một giải pháp chung có chức năng ánh xạ (chậm hơn so với bản đồ trực tiếp, nhưng đó là điều được mong đợi):

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
Tôi thích giải pháp chung nhất vì không chắc rằng tuổi tác là giá trị riêng biệt duy nhất cần thiết trong kịch bản thế giới thực.
Toft

5
Trong phần chung, thay đổi "differ.push (key)" thành "differ.push (x)" để trả về một danh sách các phần tử thực tế mà tôi thấy rất có thể sử dụng được!
Silas Hansen

15

Tôi đã bắt đầu gắn Underscore trong tất cả các dự án mới theo mặc định vì vậy tôi không bao giờ phải suy nghĩ về những vấn đề nhỏ về dữ liệu này.

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

Sản xuất [17, 35].


13

Đây là một cách khác để giải quyết điều này:

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

Tôi không biết giải pháp này nhanh như thế nào so với các giải pháp khác, nhưng tôi thích cái nhìn gọn gàng hơn. ;-)


EDIT: Được rồi, ở trên dường như là giải pháp chậm nhất trong tất cả ở đây.

Tôi đã tạo một trường hợp thử nghiệm hiệu suất tại đây: http://jsperf.com/distinc-values-from-array

Thay vì kiểm tra độ tuổi (Số nguyên), tôi chọn so sánh tên (Chuỗi).

Phương pháp 1 (giải pháp của TS) rất nhanh. Thật thú vị, Phương pháp 7 vượt trội hơn tất cả các giải pháp khác, ở đây tôi đã loại bỏ .indexOf () và sử dụng triển khai "thủ công" của nó, tránh việc gọi hàm lặp:

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

Sự khác biệt về hiệu suất khi sử dụng Safari & Firefox là đáng kinh ngạc và có vẻ như Chrome thực hiện công việc tối ưu hóa tốt nhất.

Tôi không chắc chắn chính xác tại sao các đoạn trên quá nhanh so với các đoạn khác, có lẽ ai đó khôn ngoan hơn tôi có câu trả lời. ;-)


9

sử dụng lodash

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

2
Bạn có thể giải thích làm thế nào để làm điều này với javascript đơn giản như được ngụ ý trong câu hỏi không?
Ruskin

đó là chức năng gạch dưới _.chain
vini

2
nhưng pluck () không có trong lodash.
Yash Vekaria

1
_.chain (mảng) .map ('tuổi'). unique (). value (); đã làm cho tôi.
Yash Vekaria

phiên bản 4.0 có một số thay đổi đột phá tham khảo - stackoverflow.com/a/31740263/4050261
Adarsh ​​Madrecha

7

Sử dụng Lodash

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

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

Trả về [17,35]


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

gạch dưới _.uniq(_.pluck(array,"age"))


5
Vui lòng thêm một lời giải thích làm thế nào điều này trả lời câu hỏi.
Mèo robot

2
_.pluck đã bị xóa theo hướng có lợi cho _.map
Ajax3,14

5

Đây là một giải pháp linh hoạt sử dụng giảm, cho phép ánh xạ và duy trì thứ tự chèn.

mục : Một mảng

mapper : Một hàm unary ánh xạ mục theo tiêu chí hoặc để trống để ánh xạ chính mục đó.

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

Sử dụng

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

Bạn có thể thêm nó vào nguyên mẫu Array của bạn và bỏ qua tham số vật phẩm nếu đó là phong cách của bạn ...

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

Bạn cũng có thể sử dụng Set thay vì Array để tăng tốc độ khớp.

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
cái này trông giống như O (n ^ 2)
cegprakash

4

Chỉ cần tìm thấy cái này và tôi nghĩ nó hữu ích

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

Một lần nữa sử dụng dấu gạch dưới , vì vậy nếu bạn có một đối tượng như thế này

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

nó sẽ cung cấp cho bạn các đối tượng duy nhất.

Điều gì xảy ra ở đây là indexBytrả về một bản đồ như thế này

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

và chỉ vì đó là bản đồ, tất cả các phím đều là duy nhất.

Sau đó, tôi chỉ ánh xạ danh sách này trở lại mảng.

Trong trường hợp bạn chỉ cần các giá trị riêng biệt

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

Hãy nhớ rằng chuỗi keyđược trả về dưới dạng một chuỗi vì vậy, nếu bạn cần số nguyên thay thế, bạn nên làm

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

4

tôi nghĩ rằng bạn đang tìm kiếm chức năng groupBy (sử dụng Lodash)

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

tạo ra kết quả:

17,35

Bản demo jsFiddle: http://jsfiddle.net/4J2SX/201/


3

Nếu giống như tôi, bạn thích một "chức năng" hơn mà không ảnh hưởng đến tốc độ, ví dụ này sử dụng tra cứu từ điển nhanh được bọc bên trong để giảm sự đóng cửa.

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

Theo thử nghiệm này, giải pháp của tôi nhanh gấp đôi so với câu trả lời được đề xuất


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

3

Tôi biết mã của tôi có độ dài nhỏ và độ phức tạp thời gian ít nhưng nó có thể hiểu được vì vậy tôi đã thử theo cách này.

Tôi đang cố gắng phát triển chức năng dựa trên nguyên mẫu ở đây và mã cũng thay đổi.

Ở đây, Phân biệt là chức năng nguyên mẫu của riêng tôi.

<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

Nếu bạn có Array.prototype.includes hoặc sẵn sàng polyfill nó, điều này hoạt động:

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

1

Mã dưới đây của tôi sẽ hiển thị mảng tuổi duy nhất cũng như mảng mới không có tuổi trùng lặp

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

Tôi đã tự viết bằng TypeScript, cho một trường hợp chung, giống như trong 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)));
}

Trường hợp Ucó thể băm, tất nhiên. Đối với Đối tượng, bạn có thể cần https://www.npmjs.com/package/es6-json-urdy-opesify


1

Trong trường hợp bạn cần duy nhất của toàn bộ đối tượng

const _ = require('lodash');

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

_.uniqWith(objects, _.isEqual);

[Đối tượng {x: 1, y: 2}, Đối tượng {x: 2, y: 1}]


downvoter: Tâm giải thích tại sao downvote?
cegprakash

1

Trả lời câu hỏi cũ này là khá vô nghĩa, nhưng có một câu trả lời đơn giản nói lên bản chất của Javascript. Các đối tượng trong Javascript vốn là bảng băm. Chúng ta có thể sử dụng điều này để có được một hàm băm của các khóa duy nhất:

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

Sau đó, chúng ta có thể giảm hàm băm thành một mảng các giá trị duy nhất:

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

Đấy là tất cả các thứ bạn cần. Mảng a2 chỉ chứa các lứa tuổi duy nhất.


1

Một lớp lót đơn giản với hiệu suất tuyệt vời. Nhanh hơn 6% so với các giải pháp ES6 trong các thử nghiệm của tôi .

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

@ Jeb50 Muốn thêm một dòng dễ đọc? Nhìn vào những người khác ở đây tôi thực sự không cảm thấy họ dễ đọc hay dễ hiểu. Tôi nghĩ rằng tốt nhất là đặt nó trong một chức năng mô tả những gì nó làm.
Craig

2
Với các chức năng mũi tên : array.map( o => o.age).filter( (v,i,a) => a.indexOf(v)===i). Tôi sử dụng từ khóa chức năng rất hiếm khi tôi phải đọc hai lần khi tôi thấy nó 😊
Drenai
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.