Tôi đang tìm một cách thanh lịch để xác định phần tử nào có tỷ lệ xuất hiện ( chế độ ) cao nhất trong một mảng JavaScript.
Ví dụ, trong
['pear', 'apple', 'orange', 'apple']
các 'apple'
phần tử là một trong những thường xuyên nhất.
Tôi đang tìm một cách thanh lịch để xác định phần tử nào có tỷ lệ xuất hiện ( chế độ ) cao nhất trong một mảng JavaScript.
Ví dụ, trong
['pear', 'apple', 'orange', 'apple']
các 'apple'
phần tử là một trong những thường xuyên nhất.
Câu trả lời:
Đây chỉ là chế độ. Đây là một giải pháp nhanh chóng, không được tối ưu hóa . Nó phải là O (n).
function mode(array)
{
if(array.length == 0)
return null;
var modeMap = {};
var maxEl = array[0], maxCount = 1;
for(var i = 0; i < array.length; i++)
{
var el = array[i];
if(modeMap[el] == null)
modeMap[el] = 1;
else
modeMap[el]++;
if(modeMap[el] > maxCount)
{
maxEl = el;
maxCount = modeMap[el];
}
}
return maxEl;
}
Đã có một số phát triển trong javascript kể từ năm 2009 - tôi nghĩ rằng tôi sẽ thêm một tùy chọn khác. Tôi ít quan tâm đến hiệu quả hơn cho đến khi nó thực sự là một vấn đề vì vậy định nghĩa của tôi về mã "thanh lịch" (theo quy định của OP) ủng hộ tính dễ đọc - tất nhiên là chủ quan ...
function mode(arr){
return arr.sort((a,b) =>
arr.filter(v => v===a).length
- arr.filter(v => v===b).length
).pop();
}
mode(['pear', 'apple', 'orange', 'apple']); // apple
Trong ví dụ cụ thể này, nếu hai hoặc nhiều phần tử của tập hợp có số lần xuất hiện bằng nhau thì phần tử xuất hiện muộn nhất trong mảng sẽ được trả về. Cũng cần chỉ ra rằng nó sẽ sửa đổi mảng ban đầu của bạn - điều này có thể được ngăn chặn nếu bạn muốn với một Array.slice
cuộc gọi trước.
Chỉnh sửa: đã cập nhật ví dụ với một số mũi tên béo ES6 vì năm 2015 đã xảy ra và tôi nghĩ chúng trông khá đẹp ... Nếu bạn lo lắng về khả năng tương thích ngược, bạn có thể tìm thấy điều này trong lịch sử sửa đổi .
Theo George Jempty's
yêu cầu có tài khoản thuật toán cho các mối quan hệ, tôi đề xuất một phiên bản Matthew Flaschen's
thuật toán sửa đổi .
function modeString(array) {
if (array.length == 0) return null;
var modeMap = {},
maxEl = array[0],
maxCount = 1;
for (var i = 0; i < array.length; i++) {
var el = array[i];
if (modeMap[el] == null) modeMap[el] = 1;
else modeMap[el]++;
if (modeMap[el] > maxCount) {
maxEl = el;
maxCount = modeMap[el];
} else if (modeMap[el] == maxCount) {
maxEl += "&" + el;
maxCount = modeMap[el];
}
}
return maxEl;
}
Thao tác này bây giờ sẽ trả về một chuỗi với (các) phần tử chế độ được phân tách bằng &
ký hiệu. Khi nhận được kết quả, nó có thể được phân chia trên &
phần tử đó và bạn có (các) chế độ của mình.
Một tùy chọn khác sẽ là trả về một mảng (các) phần tử chế độ như sau:
function modeArray(array) {
if (array.length == 0) return null;
var modeMap = {},
maxCount = 1,
modes = [];
for (var i = 0; i < array.length; i++) {
var el = array[i];
if (modeMap[el] == null) modeMap[el] = 1;
else modeMap[el]++;
if (modeMap[el] > maxCount) {
modes = [el];
maxCount = modeMap[el];
} else if (modeMap[el] == maxCount) {
modes.push(el);
maxCount = modeMap[el];
}
}
return modes;
}
Trong ví dụ trên, bạn sẽ có thể xử lý kết quả của hàm dưới dạng một mảng các chế độ.
modes
để [array[0]]
như giá trị ban đầu. Điều này sẽ đảm bảo rằng bạn có các bản sao trong modes
. Điều này sẽ làm các trickvar modes = []
==
để ===
thực thi bình đẳng nghiêm ngặt
Dựa trên Emissary ES6 + câu trả lời 's, bạn có thể sử dụng Array.prototype.reduce
để làm so sánh của bạn (như trái ngược với phân loại, popping và có khả năng đột biến mảng của bạn), mà tôi nghĩ rằng vẻ ngoài khá bóng bẩy.
const mode = (myArray) =>
myArray.reduce(
(a,b,i,arr)=>
(arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b),
null)
Tôi đang mặc định là null, điều này sẽ không luôn cung cấp cho bạn phản hồi trung thực nếu null là một tùy chọn khả thi mà bạn đang lọc, có thể đó có thể là đối số thứ hai tùy chọn
Nhược điểm, cũng như các giải pháp khác, là nó không xử lý 'trạng thái vẽ', nhưng điều này vẫn có thể đạt được với chức năng giảm liên quan hơn một chút.
a=['pear', 'apple', 'orange', 'apple'];
b={};
max='', maxi=0;
for(let k of a) {
if(b[k]) b[k]++; else b[k]=1;
if(maxi < b[k]) { max=k; maxi=b[k] }
}
Vì tôi đang sử dụng chức năng này như một bài kiểm tra cho người phỏng vấn, tôi đăng giải pháp của mình:
const highest = arr => (arr || []).reduce( ( acc, el ) => {
acc.k[el] = acc.k[el] ? acc.k[el] + 1 : 1
acc.max = acc.max ? acc.max < acc.k[el] ? el : acc.max : el
return acc
}, { k:{} }).max
const test = [0,1,2,3,4,2,3,1,0,3,2,2,2,3,3,2]
console.log(highest(test))
Đang thử một cách tiếp cận khai báo ở đây. Giải pháp này xây dựng một đối tượng để kiểm đếm số lần xuất hiện của mỗi từ. Sau đó, lọc đối tượng xuống một mảng bằng cách so sánh tổng số lần xuất hiện của mỗi từ với giá trị cao nhất được tìm thấy trong đối tượng.
const arr = ['hello', 'world', 'hello', 'again'];
const tally = (acc, x) => {
if (! acc[x]) {
acc[x] = 1;
return acc;
}
acc[x] += 1;
return acc;
};
const totals = arr.reduce(tally, {});
const keys = Object.keys(totals);
const values = keys.map(x => totals[x]);
const results = keys.filter(x => totals[x] === Math.max(...values));
Đã đến lúc cho một giải pháp khác:
function getMaxOccurrence(arr) {
var o = {}, maxCount = 0, maxValue, m;
for (var i=0, iLen=arr.length; i<iLen; i++) {
m = arr[i];
if (!o.hasOwnProperty(m)) {
o[m] = 0;
}
++o[m];
if (o[m] > maxCount) {
maxCount = o[m];
maxValue = m;
}
}
return maxValue;
}
Nếu sự ngắn gọn quan trọng (nó không), thì:
function getMaxOccurrence(a) {
var o = {}, mC = 0, mV, m;
for (var i=0, iL=a.length; i<iL; i++) {
m = a[i];
o.hasOwnProperty(m)? ++o[m] : o[m] = 1;
if (o[m] > mC) mC = o[m], mV = m;
}
return mV;
}
Nếu cần tránh các thành viên không tồn tại (ví dụ: mảng thưa thớt), thì cần phải kiểm tra thêm hasOwnProperty :
function getMaxOccurrence(a) {
var o = {}, mC = 0, mV, m;
for (var i=0, iL=a.length; i<iL; i++) {
if (a.hasOwnProperty(i)) {
m = a[i];
o.hasOwnProperty(m)? ++o[m] : o[m] = 1;
if (o[m] > mC) mC = o[m], mV = m;
}
}
return mV;
}
getMaxOccurrence([,,,,,1,1]); // 1
Các câu trả lời khác ở đây sẽ trả về không xác định .
Một giải pháp JS khác từ: https://www.w3resource.com/javascript-exercises/javascript-array-exercise-8.php
Cũng có thể thử điều này:
let arr =['pear', 'apple', 'orange', 'apple'];
function findMostFrequent(arr) {
let mf = 1;
let m = 0;
let item;
for (let i = 0; i < arr.length; i++) {
for (let j = i; j < arr.length; j++) {
if (arr[i] == arr[j]) {
m++;
if (m > mf) {
mf = m;
item = arr[i];
}
}
}
m = 0;
}
return item;
}
findMostFrequent(arr); // apple
Đây là một cách khác của ES6 để làm điều đó với độ phức tạp O (n)
const result = Object.entries(
['pear', 'apple', 'orange', 'apple'].reduce((previous, current) => {
if (previous[current] === undefined) previous[current] = 1;
else previous[current]++;
return previous;
}, {})).reduce((previous, current) => (current[1] >= previous[1] ? current : previous))[0];
console.log("Max value : " + result);
function mode(arr){
return arr.reduce(function(counts,key){
var curCount = (counts[key+''] || 0) + 1;
counts[key+''] = curCount;
if (curCount > counts.max) { counts.max = curCount; counts.mode = key; }
return counts;
}, {max:0, mode: null}).mode
}
Đây là giải pháp của tôi cho vấn đề này nhưng với các con số và sử dụng tính năng 'Đặt' mới. Nó không hiệu quả lắm nhưng tôi chắc chắn đã rất vui khi viết nó và nó hỗ trợ nhiều giá trị tối đa.
const mode = (arr) => [...new Set(arr)]
.map((value) => [value, arr.filter((v) => v === value).length])
.sort((a,b) => a[1]-b[1])
.reverse()
.filter((value, i, a) => a.indexOf(value) === i)
.filter((v, i, a) => v[1] === a[0][1])
.map((v) => v[0])
mode([1,2,3,3]) // [3]
mode([1,1,1,1,2,2,2,2,3,3,3]) // [1,2]
Nhân tiện, không sử dụng nó để sản xuất, đây chỉ là một minh họa về cách bạn có thể giải quyết nó chỉ với các hàm ES6 và Array.
Đây là giải pháp của tôi: -
function frequent(number){
var count = 0;
var sortedNumber = number.sort();
var start = number[0], item;
for(var i = 0 ; i < sortedNumber.length; i++){
if(start === sortedNumber[i] || sortedNumber[i] === sortedNumber[i+1]){
item = sortedNumber[i]
}
}
return item
}
console.log( frequent(['pear', 'apple', 'orange', 'apple']))
Vì lợi ích của mã thực sự dễ đọc, dễ bảo trì, tôi chia sẻ điều này:
function getMaxOcurrences(arr = []) {
let item = arr[0];
let ocurrencesMap = {};
for (let i in arr) {
const current = arr[i];
if (ocurrencesMap[current]) ocurrencesMap[current]++;
else ocurrencesMap[current] = 1;
if (ocurrencesMap[item] < ocurrencesMap[current]) item = current;
}
return {
item: item,
ocurrences: ocurrencesMap[item]
};
}
Hy vọng nó sẽ giúp ai đó;)!
Giải pháp này có thể trả về nhiều phần tử của một mảng trong trường hợp ràng buộc. Ví dụ, một mảng
arr = [ 3, 4, 3, 6, 4, ];
có hai giá trị chế độ: 3
và 6
.
Đây là giải pháp.
function find_mode(arr) {
var max = 0;
var maxarr = [];
var counter = [];
var maxarr = [];
arr.forEach(function(){
counter.push(0);
});
for(var i = 0;i<arr.length;i++){
for(var j=0;j<arr.length;j++){
if(arr[i]==arr[j])counter[i]++;
}
}
max=this.arrayMax(counter);
for(var i = 0;i<arr.length;i++){
if(counter[i]==max)maxarr.push(arr[i]);
}
var unique = maxarr.filter( this.onlyUnique );
return unique;
};
function arrayMax(arr) {
var len = arr.length, max = -Infinity;
while (len--) {
if (arr[len] > max) {
max = arr[len];
}
}
return max;
};
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
var mode = 0;
var c = 0;
var num = new Array();
var value = 0;
var greatest = 0;
var ct = 0;
Lưu ý: ct là độ dài của mảng.
function getMode()
{
for (var i = 0; i < ct; i++)
{
value = num[i];
if (i != ct)
{
while (value == num[i + 1])
{
c = c + 1;
i = i + 1;
}
}
if (c > greatest)
{
greatest = c;
mode = value;
}
c = 0;
}
}
const mode = (str) => {
return str
.split(' ')
.reduce((data, key) => {
let counter = data.map[key] + 1 || 1
data.map[key] = counter
if (counter > data.counter) {
data.counter = counter
data.mode = key
}
return data
}, {
counter: 0,
mode: null,
map: {}
})
.mode
}
console.log(mode('the t-rex is the greatest of them all'))
Hãy thử nó quá, điều này không tính đến phiên bản trình duyệt.
function mode(arr){
var a = [],b = 0,occurrence;
for(var i = 0; i < arr.length;i++){
if(a[arr[i]] != undefined){
a[arr[i]]++;
}else{
a[arr[i]] = 1;
}
}
for(var key in a){
if(a[key] > b){
b = a[key];
occurrence = key;
}
}
return occurrence;
}
alert(mode(['segunda','terça','terca','segunda','terça','segunda']));
Xin lưu ý rằng hàm này trả về lần xuất hiện mới nhất trong mảng khi 2 hoặc nhiều mục nhập xuất hiện cùng một số lần!
Đây là phiên bản hiện đại sử dụng bản đồ tích hợp (vì vậy nó hoạt động trên nhiều thứ có thể chuyển đổi thành chuỗi duy nhất):
'use strict';
const histogram = iterable => {
const result = new Map();
for (const x of iterable) {
result.set(x, (result.get(x) || 0) + 1);
}
return result;
};
const mostCommon = iterable => {
let maxCount = 0;
let maxKey;
for (const [key, count] of histogram(iterable)) {
if (count > maxCount) {
maxCount = count;
maxKey = key;
}
}
return maxKey;
};
console.log(mostCommon(['pear', 'apple', 'orange', 'apple']));
Tôi đoán bạn có hai cách tiếp cận. Cả hai đều có lợi thế.
Sắp xếp rồi Đếm hoặc Lặp lại và sử dụng bảng băm để đếm cho bạn.
Bảng băm rất hay vì sau khi xử lý xong, bạn cũng có tất cả các phần tử riêng biệt. Mặc dù vậy, nếu bạn có hàng triệu mục, bảng băm có thể sử dụng nhiều bộ nhớ nếu tỷ lệ trùng lặp thấp. Phương pháp sắp xếp, sau đó đếm sẽ có dấu chân bộ nhớ kiểm soát được nhiều hơn.
var array = [1, 3, 6, 6, 6, 6, 7, 7, 12, 12, 17],
c = {}, // counters
s = []; // sortable array
for (var i=0; i<array.length; i++) {
c[array[i]] = c[array[i]] || 0; // initialize
c[array[i]]++;
} // count occurrences
for (var key in c) {
s.push([key, c[key]])
} // build sortable array from counters
s.sort(function(a, b) {return b[1]-a[1];});
var firstMode = s[0][0];
console.log(firstMode);
Bạn có thể thử điều này:
// using splice()
// get the element with the highest occurence in an array
function mc(a) {
var us = [], l;
// find all the unique elements in the array
a.forEach(function (v) {
if (us.indexOf(v) === -1) {
us.push(v);
}
});
l = us.length;
while (true) {
for (var i = 0; i < l; i ++) {
if (a.indexOf(us[i]) === -1) {
continue;
} else if (a.indexOf(us[i]) != -1 && a.length > 1) {
// just delete it once at a time
a.splice(a.indexOf(us[i]), 1);
} else {
// default to last one
return a[0];
}
}
}
}
// using string.match method
function su(a) {
var s = a.join(),
uelms = [],
r = {},
l,
i,
m;
a.forEach(function (v) {
if (uelms.indexOf(v) === -1) {
uelms.push(v);
}
});
l = uelms.length;
// use match to calculate occurance times
for (i = 0; i < l; i ++) {
r[uelms[i]] = s.match(new RegExp(uelms[i], 'g')).length;
}
m = uelms[0];
for (var p in r) {
if (r[p] > r[m]) {
m = p;
} else {
continue;
}
}
return m;
}
Bạn có thể giải nó với độ phức tạp O (n)
var arr = [1,3,54,56,6,6,1,6];
var obj = {};
/* first convert the array in to object with unique elements and number of times each element is repeated */
for(var i = 0; i < arr.length; i++)
{
var x = arr[i];
if(!obj[x])
obj[x] = 1;
else
obj[x]++;
}
console.log(obj);//just for reference
/* now traverse the object to get the element */
var index = 0;
var max = 0;
for(var obIndex in obj)
{
if(obj[obIndex] > max)
{
max = obj[obIndex];
index = obIndex;
}
}
console.log(index+" got maximum time repeated, with "+ max +" times" );
Chỉ cần sao chép và dán vào bảng điều khiển chrome để chạy đoạn mã trên.
Chức năng này là chức năng chung cho mọi loại thông tin. Nó đếm sự xuất hiện của các phần tử và sau đó trả về mảng với các phần tử xuất hiện tối đa.
function mode () {
var arr = [].slice.call(arguments);
if ((args.length == 1) && (typeof args[0] === "object")) {
args = args[0].mode();
}
var obj = {};
for(var i = 0; i < arr.length; i++) {
if(obj[arr[i]] === undefined) obj[arr[i]] = 1;
else obj[arr[i]]++;
}
var max = 0;
for (w in obj) {
if (obj[w] > max) max = obj[w];
}
ret_val = [];
for (w in obj) {
if (obj[w] == max) ret_val.push(w);
}
return ret_val;
}
function mode(){
var input = $("input").val().split(",");
var mode = [];
var m = [];
var p = [];
for(var x = 0;x< input.length;x++){
if(m.indexOf(input[x])==-1){
m[m.length]=input[x];
}}
for(var x = 0; x< m.length;x++){
p[x]=0;
for(var y = 0; y<input.length;y++){
if(input[y]==m[x]){
p[x]++;
}}}
for(var x = 0;x< p.length;x++){
if(p[x] ==(Math.max.apply(null, p))){
mode.push(m[x]);
}}
$("#output").text(mode);}
Đây là cách của tôi. Tôi cố gắng nhóm dữ liệu nắm tay.
const _ = require("underscore")
var test = [ 1, 1, 2, 1 ];
var groupResult = _.groupBy(test, (e)=> e);
GroupResult phải là
{
1: [1, 1, 1]
2: [2]
}
Sau đó, tìm thuộc tính có mảng dài nhất
function findMax(groupResult){
var maxArr = []
var max;
for(var item in groupResult){
if(!max) {
max = { value:item, count: groupResult[item].length } ;
maxArr.push(max);
continue;
}
if(max.count < groupResult[item].length){
maxArr = [];
max = { value:item, count: groupResult[item].length }
maxArr.push(max)
} else if(max === groupResult[item].length)
maxArr.push({ value:item, count: groupResult[item].length })
}
return maxArr;
}
Mã hoàn chỉnh trông giống như
const _ = require("underscore")
var test = [ 1, 1, 2, 1 ];
var groupResult= _.groupBy(test, (e)=> e);
console.log(findMax(groupResult)[0].value);
function findMax(groupResult){
var maxArr = []
var max;
for(var item in groupResult){
if(!max) {
max = { value:item, count: groupResult[item].length } ;
maxArr.push(max);
continue;
}
if(max.count < groupResult[item].length){
maxArr = [];
max = { value:item, count: groupResult[item].length }
maxArr.push(max)
} else if(max === groupResult[item].length)
maxArr.push({ value:item, count: groupResult[item].length })
}
return maxArr;
}
var cats = ['Tom','Fluffy','Tom','Bella','Chloe','Tom','Chloe'];
var counts = {};
var compare = 0;
var mostFrequent;
(function(array){
for(var i = 0, len = array.length; i < len; i++){
var word = array[i];
if(counts[word] === undefined){
counts[word] = 1;
}else{
counts[word] = counts[word] + 1;
}
if(counts[word] > compare){
compare = counts[word];
mostFrequent = cats[i];
}
}
return mostFrequent;
})(cats);
Với ES6, bạn có thể chuỗi phương thức như sau:
function findMostFrequent(arr) {
return arr
.reduce((acc, cur, ind, arr) => {
if (arr.indexOf(cur) === ind) {
return [...acc, [cur, 1]];
} else {
acc[acc.indexOf(acc.find(e => e[0] === cur))] = [
cur,
acc[acc.indexOf(acc.find(e => e[0] === cur))][1] + 1
];
return acc;
}
}, [])
.sort((a, b) => b[1] - a[1])
.filter((cur, ind, arr) => cur[1] === arr[0][1])
.map(cur => cur[0]);
}
console.log(findMostFrequent(['pear', 'apple', 'orange', 'apple']));
console.log(findMostFrequent(['pear', 'apple', 'orange', 'apple', 'pear']));
Nếu hai phần tử có cùng một lần xuất hiện, nó sẽ trả về cả hai phần tử đó. Và nó hoạt động với bất kỳ loại phần tử nào.
arr
bên trong phạm vi mà biến đó đã được xác định là một tham số. Điều này có thể dẫn đến lỗi tùy thuộc vào trình duyệt được sử dụng.
arr
được giới thiệu bởi arr.indexOf(cur)
? Tham số trên cùng, hay tham số bên trong giảm ??