Я ищу элегантный способ определить, какой элемент имеет наибольшее вхождение ( режим ) в массиве JavaScript.
Например, в
['pear', 'apple', 'orange', 'apple']
'apple'
элемент является наиболее частой один.
javascript
mode
тиски
источник
источник
Ответы:
Это просто режим. Вот
быстрое неоптимизированноерешение. Это должно быть 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; }
источник
С 2009 года в javascript произошли некоторые изменения - я подумал, что добавлю еще один вариант. Меня меньше беспокоит эффективность, пока это не станет проблемой, поэтому мое определение «элегантного» кода (как предусмотрено OP) способствует удобочитаемости - что, конечно, субъективно ...
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
В этом конкретном примере, если два или более элемента набора имеют одинаковые вхождения, будет возвращен тот, который появляется последним в массиве. Также стоит отметить, что он изменит ваш исходный массив, что можно предотвратить, если вы хотите,
Array.slice
предварительно позвонив.Изменить: обновлен пример с некоторыми жирными стрелками ES6, потому что произошел 2015 год, и я думаю, что они выглядят красиво ... Если вас беспокоит обратная совместимость, вы можете найти это в истории изменений .
источник
В соответствии с
George Jempty's
просьбой о том, чтобы алгоритм учитывал связи, я предлагаю модифицированный вариантMatthew Flaschen's
алгоритма.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; }
Теперь будет возвращена строка с элементами режима, разделенными
&
символом. Когда результат получен, его можно разделить на этот&
элемент, и у вас будет свой режим (ы).Другой вариант - вернуть массив элементов режима, например:
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; }
В приведенном выше примере вы сможете обработать результат функции как массив режимов.
источник
modes
в[array[0]]
качестве начального значения. Это гарантирует, что у вас есть дубликатыmodes
. Это должноvar modes = []
==
на,===
чтобы обеспечить строгое равенствоОсновываясь на ответе Emissary ES6 +, вы можете использовать его
Array.prototype.reduce
для сравнения (в отличие от сортировки, извлечения и потенциального изменения вашего массива), что, на мой взгляд, выглядит довольно гладко.const mode = (myArray) => myArray.reduce( (a,b,i,arr)=> (arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b), null)
По умолчанию я использую значение null, что не всегда дает вам правдивый ответ, если значение null - это возможный вариант, который вы фильтруете, возможно, это может быть необязательный второй аргумент
Обратной стороной, как и в случае с различными другими решениями, является то, что он не обрабатывает «состояния рисования», но этого все же можно достичь с помощью немного более сложной функции сокращения.
источник
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] } }
источник
Поскольку я использую эту функцию в качестве теста для интервьюеров, я публикую свое решение:
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))
источник
Попробуем здесь декларативный подход. Это решение создает объект для подсчета вхождений каждого слова. Затем фильтрует объект до массива, сравнивая общее количество вхождений каждого слова с наибольшим значением, найденным в объекте.
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));
источник
Время для другого решения:
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; }
Если краткость имеет значение (а это не так), то:
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; }
Если необходимо избегать несуществующих членов (например, разреженного массива), требуется дополнительный тест 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
Другие ответы здесь вернут undefined .
источник
Другое решение JS от: https://www.w3resource.com/javascript-exercises/javascript-array-exercise-8.php
Можете попробовать и это:
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
источник
Вот еще один способ ES6 сделать это со сложностью 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 }
источник
Вот мое решение этой проблемы, но с числами и с использованием новой функции «Установить». Это не очень производительно, но мне определенно было очень весело писать это, и он поддерживает несколько максимальных значений.
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]
Кстати, не используйте это для производства, это просто иллюстрация того, как вы можете решить эту проблему только с помощью функций ES6 и Array.
источник
Вот мое решение: -
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']))
источник
Ради действительно легкого для чтения, поддерживаемого кода я делюсь следующим:
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] }; }
Надеюсь, это кому-то поможет;)!
источник
Это решение может возвращать несколько элементов массива в случае ничьей. Например, массив
arr = [ 3, 4, 3, 6, 4, ];
имеет два значения режима:
3
и6
.Вот решение.
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;
Примечание: ct - это длина массива.
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'))
источник
function mode(array){ var set = Array.from(new Set(array)); var counts = set.map(a=>array.filter(b=>b==a).length); var indices = counts.map((a,b)=>Math.max(...counts)===a?b:0).filter(b=>b!==0); var mode = indices.map(a=>set[a]); return mode; }
источник
Попробуйте тоже, это не касается версии браузера учетной записи.
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']));
источник
// O(n) var arr = [1, 2, 3, 2, 3, 3, 5, 6]; var duplicates = {}; max = ''; maxi = 0; arr.forEach((el) => { duplicates[el] = duplicates[el] + 1 || 1; if (maxi < duplicates[el]) { max = el; maxi = duplicates[el]; } }); console.log(max);
источник
Вот современная версия со встроенными картами (так что она работает не только с вещами, которые можно преобразовать в уникальные строки):
'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']));
источник
Думаю, у вас есть два подхода. У обоих есть преимущества.
Отсортируйте, затем Подсчитайте или Прокрутите и используйте хеш-таблицу, чтобы сделать подсчет за вас.
Хеш-таблица хороша тем, что после завершения обработки у вас также есть все отдельные элементы. Если бы у вас были миллионы элементов, хеш-таблица могла бы использовать много памяти, если скорость дублирования низкая. Подход «сортировка, затем подсчет» будет иметь гораздо более контролируемый объем памяти.
источник
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);
источник
Вы можете попробовать это:
// 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; }
источник
Вы можете решить это за 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" );
Просто скопируйте и вставьте в хромированную консоль, чтобы запустить приведенный выше код.
источник
Эта функция является универсальной для каждого типа информации. Он считает появление элементов, а затем возвращает массив с максимальным количеством встречающихся элементов.
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);}
источник
Вот мой путь. Пытаюсь сгруппировать данные кулаком.
const _ = require("underscore") var test = [ 1, 1, 2, 1 ]; var groupResult = _.groupBy(test, (e)=> e);
GroupResult должен быть
{ 1: [1, 1, 1] 2: [2] }
Затем найдите свойство, имеющее самый длинный массив
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; }
Полный код выглядит как
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);
источник
С ES6 вы можете связать метод следующим образом:
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']));
Если два элемента имеют одно и то же вхождение, он вернет их оба. И он работает с любым типом элемента.
источник
arr
внутри области, где эта переменная уже определена как параметр. Это может привести к ошибкам в зависимости от того, какой браузер используется.arr
ссылаетсяarr.indexOf(cur)
? Верхний параметр или тот, который находится внутри сокращения ??