Cách nhóm một mảng các đối tượng theo khóa


67
42
Phạm Vĩnh Đức
3 năm trước

Có ai biết một cách (lodash nếu có thể) để nhóm một mảng các đối tượng bằng một khóa đối tượng sau đó tạo ra một mảng các đối tượng mới dựa trên việc phân nhóm không? Ví dụ, tôi có một loạt các đối tượng xe hơi:

var cars = [
    {
        'make': 'audi',
        'model': 'r8',
        'year': '2012'
    }, {
        'make': 'audi',
        'model': 'rs5',
        'year': '2013'
    }, {
        'make': 'ford',
        'model': 'mustang',
        'year': '2012'
    }, {
        'make': 'ford',
        'model': 'fusion',
        'year': '2015'
    }, {
        'make': 'kia',
        'model': 'optima',
        'year': '2012'
    },
];

Tôi muốn tạo ra một loạt các đối tượng xe hơi được nhóm theo make:

var cars = {
    'audi': [
        {
            'model': 'r8',
            'year': '2012'
        }, {
            'model': 'rs5',
            'year': '2013'
        },
    ],

    'ford': [
        {
            'model': 'mustang',
            'year': '2012'
        }, {
            'model': 'fusion',
            'year': '2015'
        }
    ],

    'kia': [
        {
            'model': 'optima',
            'year': '2012'
        }
    ]
}
Hữu ích 67 Yêu thích 42 Chia sẻ Viết bình luận 3
Không hữu ích

kết quả của bạn không hợp lệ.

Hữu ích 2 · Không hữu ích · Trả lời 0

Bạn đã nhìn vào groupBy?

Hữu ích 0 · Không hữu ích · Trả lời 0

Có một cách tiếp cận tương tự để có được một Bản đồ thay vì một đối tượng?

Hữu ích 0 · Không hữu ích · Trả lời 0

15 Trả lời


49
Trịnh Đoan Trang
3 năm trước

Câu trả lời của Timo là cách tôi sẽ làm điều đó. Đơn giản _.groupByvà cho phép một số trùng lặp trong các đối tượng trong cấu trúc được nhóm.

Tuy nhiên, OP cũng yêu cầu makeloại bỏ các phím trùng lặp . Nếu bạn muốn đi tất cả các cách:

var grouped = _.mapValues(_.groupBy(cars, 'make'),
                          clist => clist.map(car => _.omit(car, 'make')));

console.log(grouped);

Sản lượng:

{ audi:
   [ { model: 'r8', year: '2012' },
     { model: 'rs5', year: '2013' } ],
  ford:
   [ { model: 'mustang', year: '2012' },
     { model: 'fusion', year: '2015' } ],
  kia: [ { model: 'optima', year: '2012' } ] }

Nếu bạn muốn làm điều này bằng Underscore.js, lưu ý rằng phiên bản của _.mapValuesnó được gọi _.mapObject.

Hữu ích 49 Trả lời hay nhất Chia sẻ Viết bình luận 0
Không hữu ích

151
Hoàng Việt Phong
3 năm trước

Trong Javascript đơn giản, bạn có thể sử dụng Array#reducevới một đối tượng

var cars = [{ make: 'audi', model: 'r8', year: '2012' }, { make: 'audi', model: 'rs5', year: '2013' }, { make: 'ford', model: 'mustang', year: '2012' }, { make: 'ford', model: 'fusion', year: '2015' }, { make: 'kia', model: 'optima', year: '2012' }],
    result = cars.reduce(function (r, a) {
        r[a.make] = r[a.make] || [];
        r[a.make].push(a);
        return r;
    }, Object.create(null));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Hữu ích 151 Chia sẻ Viết bình luận 0
Không hữu ích

44
Trịnh Minh Danh
3 năm trước

Bạn đang tìm kiếm _.groupBy().

Việc xóa tài sản mà bạn đang nhóm khỏi các đối tượng sẽ là chuyện nhỏ nếu được yêu cầu:

var cars = [{'make':'audi','model':'r8','year':'2012'},{'make':'audi','model':'rs5','year':'2013'},{'make':'ford','model':'mustang','year':'2012'},{'make':'ford','model':'fusion','year':'2015'},{'make':'kia','model':'optima','year':'2012'},];

var grouped = _.groupBy(cars, function(car) {
  return car.make;
});

console.log(grouped);
<script src='https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js'></script>


Là một phần thưởng, bạn nhận được cú pháp thậm chí còn đẹp hơn với các hàm mũi tên ES6:

const grouped = _.groupBy(cars, car => car.make);
Hữu ích 44 Chia sẻ Viết bình luận 5
Không hữu ích

Và nếu bạn muốn nó vẫn ngắn hơn, var grouped = _.groupBy(cars, 'make');Không cần một chức năng nào cả, nếu người truy cập là một tên thuộc tính đơn giản.

Hữu ích 12 · Không hữu ích · Trả lời 0

Chữ '_' là viết tắt của từ gì?

Hữu ích 1 · Không hữu ích · Trả lời 0

hoàn hảo, cảm ơn bạn

Hữu ích 0 · Không hữu ích · Trả lời 0

@AdrianGrzywaczewski đó là quy ước mặc định cho khoảng cách tên 'lodash' hoặc 'gạch dưới'. Bây giờ các librairies là mô-đun, nó không còn cần thiết, tức là. npmjs.com/package/lodash.groupby

Hữu ích 0 · Không hữu ích · Trả lời 0

Và làm thế nào tôi có thể tương tác trong kết quả?

Hữu ích 0 · Không hữu ích · Trả lời 0

22
Hoàng Hạnh Như
2 năm trước

Phiên bản ngắn để nhóm một mảng các đối tượng theo một khóa nhất định trong es6:

result = array.reduce((h, obj) => Object.assign(h, { [obj.key]:( h[obj.key] || [] ).concat(obj) }), {})

Phiên bản dài hơn:

result = array.reduce(function(h, obj) {
  h[obj.key] = (h[obj.key] || []).concat(obj);
  return h; 
}, {})

Nó xuất hiện câu hỏi ban đầu hỏi làm thế nào để nhóm xe bằng cách thực hiện, nhưng bỏ qua việc thực hiện trong mỗi nhóm. Vì vậy, câu trả lời sẽ như thế này:

result = cars.reduce((h, {model,year,make}) => {
  return Object.assign(h, { [make]:( h[make] || [] ).concat({model,year})})
}, {})
Hữu ích 22 Chia sẻ Viết bình luận 3
Không hữu ích

đây chắc chắn không phải là es5

Hữu ích 0 · Không hữu ích · Trả lời 0

Nó chỉ hoạt động! Bất kỳ ai có thể xây dựng chức năng giảm này?

Hữu ích 0 · Không hữu ích · Trả lời 0

Tôi thích cả hai câu trả lời của bạn, nhưng tôi thấy cả hai đều cung cấp trường "make" với tư cách là thành viên của mỗi mảng "make". Tôi đã cung cấp câu trả lời dựa trên câu hỏi của bạn nơi đầu ra được phân phối khớp với đầu ra dự kiến. Cảm ơn!

Hữu ích 0 · Không hữu ích · Trả lời 0

9
Trần Ðình Lộc
2 năm trước

Đây là groupBychức năng rất riêng của bạn , đó là sự khái quát hóa mã từ: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore

function groupBy(xs, f) {
  return xs.reduce((r, v, i, a, k = f(v)) => ((r[k] || (r[k] = [])).push(v), r), {});
}

const cars = [{ make: 'audi', model: 'r8', year: '2012' }, { make: 'audi', model: 'rs5', year: '2013' }, { make: 'ford', model: 'mustang', year: '2012' }, { make: 'ford', model: 'fusion', year: '2015' }, { make: 'kia', model: 'optima', year: '2012' }];

const result = groupBy(cars, (c) => c.make);
console.log(result);

Hữu ích 9 Chia sẻ Viết bình luận 0
Không hữu ích

7
Ngô Hải Phong
3 năm trước

Bạn có thể cố gắng sửa đổi đối tượng bên trong hàm được gọi là mỗi lần lặp bởi _.groupBy func. Lưu ý rằng mảng nguồn thay đổi các yếu tố của mình!

var res = _.groupBy(cars,(car)=>{
    const makeValue=car.make;
    delete car.make;
    return makeValue;
})
console.log(res);
console.log(cars);
Hữu ích 7 Chia sẻ Viết bình luận 3
Không hữu ích

Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do giải quyết vấn đề này thực sự sẽ giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ! Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những hạn chế và giả định được áp dụng.

Hữu ích 1 · Không hữu ích · Trả lời 0

Ok, cảm ơn lời đề nghị của bạn!

Hữu ích 0 · Không hữu ích · Trả lời 0

Có vẻ như câu trả lời tốt nhất cho tôi vì bạn chỉ đi qua mảng một lần để có được kết quả mong muốn. Không cần sử dụng chức năng khác để xóa thuộc maketính và nó cũng dễ đọc hơn.

Hữu ích 0 · Không hữu ích · Trả lời 0

2
Ngô Quang Anh
2 năm trước

Nó cũng có thể với một forvòng lặp đơn giản :

 const result = {};

 for(const {make, model, year} of cars) {
   if(!result[make]) result[make] = [];
   result[make].push({ model, year });
 }
Hữu ích 2 Chia sẻ Viết bình luận 0
Không hữu ích

2
Bùi Nhật Hùng
2 năm trước

Tôi sẽ để lại REAL GROUP BYví dụ về Mảng JS giống hệt nhiệm vụ này ở đây

const inputArray = [ 
    { Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
    { Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
    { Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
    { Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
    { Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
    { Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
    { Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
    { Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];

var outObject = inputArray.reduce(function(a, e) {
  // GROUP BY estimated key (estKey), well, may be a just plain key
  // a -- Accumulator result object
  // e -- sequentally checked Element, the Element that is tested just at this itaration

  // new grouping name may be calculated, but must be based on real value of real field
  let estKey = (e['Phase']); 

  (a[estKey] ? a[estKey] : (a[estKey] = null || [])).push(e);
  return a;
}, {});

console.log(outObject);

Làm thế nào để làm thế nào để làm gì đó tốt hơn được không! УУ, товари!

Hữu ích 2 Chia sẻ Viết bình luận 0
Không hữu ích

2
Vũ Thiện Ngôn
1 năm trước

Tạo một phương thức có thể được sử dụng lại

Array.prototype.groupBy = function(prop) {
      return this.reduce(function(groups, item) {
        const val = item[prop]
        groups[val] = groups[val] || []
        groups[val].push(item)
        return groups
      }, {})
    };

Sau đó, bên dưới bạn có thể nhóm theo bất kỳ tiêu chí

const groupByMake = cars.groupBy('make');
        console.log(groupByMake);

var cars = [
    {
        'make': 'audi',
        'model': 'r8',
        'year': '2012'
    }, {
        'make': 'audi',
        'model': 'rs5',
        'year': '2013'
    }, {
        'make': 'ford',
        'model': 'mustang',
        'year': '2012'
    }, {
        'make': 'ford',
        'model': 'fusion',
        'year': '2015'
    }, {
        'make': 'kia',
        'model': 'optima',
        'year': '2012'
    },
];
  //re-usable method
Array.prototype.groupBy = function(prop) {
	  return this.reduce(function(groups, item) {
		const val = item[prop]
		groups[val] = groups[val] || []
		groups[val].push(item)
		return groups
	  }, {})
	};
  
 // initiate your groupBy. Notice the recordset Cars and the field Make....
  const groupByMake = cars.groupBy('make');
		console.log(groupByMake);
    
    //At this point we have objects. You can use Object.keys to return an array

Hữu ích 2 Chia sẻ Viết bình luận 0
Không hữu ích

2
Hoàng Bảo Quốc
1 năm trước

Đối với trường hợp khóa có thể là null và chúng tôi muốn nhóm chúng thành những người khác

var cars = [{'make':'audi','model':'r8','year':'2012'},{'make':'audi','model':'rs5','year':'2013'},{'make':'ford','model':'mustang','year':'2012'},{'make':'ford','model':'fusion','year':'2015'},{'make':'kia','model':'optima','year':'2012'},
            {'make':'kia','model':'optima','year':'2033'},
            {'make':null,'model':'zen','year':'2012'},
            {'make':null,'model':'blue','year':'2017'},

           ];


 result = cars.reduce(function (r, a) {
        key = a.make || 'others';
        r[key] = r[key] || [];
        r[key].push(a);
        return r;
    }, Object.create(null));
Hữu ích 2 Chia sẻ Viết bình luận 0
Không hữu ích

1
Dương Vĩnh Sơn
1 năm trước

Chỉ cần thử cái này nó hoạt động tốt cho tôi.

let grouped = _.groupBy(cars, 'make');

Hữu ích 1 Chia sẻ Viết bình luận 2
Không hữu ích

Uncaught ReferenceError: _ không được xác định - bạn nên rõ ràng rằng giải pháp của bạn yêu cầu cài đặt thư viện của bên thứ 3 chỉ để giải quyết vấn đề này.

Hữu ích 1 · Không hữu ích · Trả lời 0

xin lỗi, tôi nghĩ rằng mọi người đều biết _ đứng và chủ yếu được sử dụng cho lib lodash. Vì vậy, bạn cần phải sử dụng lodash. xin vui lòng đọc câu hỏi để bạn sẽ biết anh ấy / cô ấy đang yêu cầu lodash. vậy, cám ơn. tôi sẽ nhớ điều này. và không bao giờ quên viết lib.

Hữu ích 1 · Không hữu ích · Trả lời 0

1
Trịnh Hương Trà
1 năm trước

var cars = [{
  make: 'audi',
  model: 'r8',
  year: '2012'
}, {
  make: 'audi',
  model: 'rs5',
  year: '2013'
}, {
  make: 'ford',
  model: 'mustang',
  year: '2012'
}, {
  make: 'ford',
  model: 'fusion',
  year: '2015'
}, {
  make: 'kia',
  model: 'optima',
  year: '2012'
}].reduce((r, a) => {
  r[a.make] = [...r[a.make] || [], a];
  return r;
}, {});

console.log(cars);

Hữu ích 1 Chia sẻ Viết bình luận 0
Không hữu ích

1
Tạ Lục Bình
1 năm trước
function groupBy(data, property) {
  return data.reduce((acc, obj) => {
    const key = obj[property];
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(obj);
    return acc;
  }, {});
}
groupBy(people, 'age');
Hữu ích 1 Chia sẻ Viết bình luận 0
Không hữu ích

0
Đỗ Nguyên Hùng
2 năm trước

Bạn cũng có thể sử dụng array#forEach()phương thức như thế này:

const cars = [{ make: 'audi', model: 'r8', year: '2012' }, { make: 'audi', model: 'rs5', year: '2013' }, { make: 'ford', model: 'mustang', year: '2012' }, { make: 'ford', model: 'fusion', year: '2015' }, { make: 'kia', model: 'optima', year: '2012' }];

let newcars = {}

cars.forEach(car => {
  newcars[car.make] ? // check if that array exists or not in newcars object
    newcars[car.make].push({model: car.model, year: car.year})  // just push
   : (newcars[car.make] = [], newcars[car.make].push({model: car.model, year: car.year})) // create a new array and push
})

console.log(newcars);

Hữu ích 0 Chia sẻ Viết bình luận 0
Không hữu ích

0
Nguyễn Ðức Trí
1 năm trước

Tôi thích câu trả lời @metakunfu, nhưng nó không cung cấp chính xác đầu ra dự kiến. Đây là một bản cập nhật loại bỏ "make" trong tải trọng JSON cuối cùng.

var cars = [
    {
        'make': 'audi',
        'model': 'r8',
        'year': '2012'
    }, {
        'make': 'audi',
        'model': 'rs5',
        'year': '2013'
    }, {
        'make': 'ford',
        'model': 'mustang',
        'year': '2012'
    }, {
        'make': 'ford',
        'model': 'fusion',
        'year': '2015'
    }, {
        'make': 'kia',
        'model': 'optima',
        'year': '2012'
    },
];

result = cars.reduce((h, car) => Object.assign(h, { [car.make]:( h[car.make] || [] ).concat({model: car.model, year: car.year}) }), {})

console.log(JSON.stringify(result));

Đầu ra:

{  
   "audi":[  
      {  
         "model":"r8",
         "year":"2012"
      },
      {  
         "model":"rs5",
         "year":"2013"
      }
   ],
   "ford":[  
      {  
         "model":"mustang",
         "year":"2012"
      },
      {  
         "model":"fusion",
         "year":"2015"
      }
   ],
   "kia":[  
      {  
         "model":"optima",
         "year":"2012"
      }
   ]
}
Hữu ích 0 Chia sẻ Viết bình luận 0
Không hữu ích

Trả lời của bạn

Xem trước nội dung