Ich suche nach einer eleganten Methode, um festzustellen, welches Element in einem JavaScript-Array am häufigsten vorkommt ( Modus ).
Zum Beispiel in
['pear', 'apple', 'orange', 'apple']
Das 'apple'
Element ist das häufigste.
Ich suche nach einer eleganten Methode, um festzustellen, welches Element in einem JavaScript-Array am häufigsten vorkommt ( Modus ).
Zum Beispiel in
['pear', 'apple', 'orange', 'apple']
Das 'apple'
Element ist das häufigste.
Antworten:
Dies ist nur der Modus. Hier ist eine schnelle, nicht optimierte Lösung. Es sollte O (n) sein.
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;
}
Seit 2009 gibt es einige Entwicklungen in Javascript - ich dachte, ich würde eine weitere Option hinzufügen. Ich bin weniger mit Effizienz beschäftigt, bis es tatsächlich ein Problem ist, daher begünstigt meine Definition von "elegantem" Code (wie vom OP festgelegt) die Lesbarkeit - was natürlich subjektiv ist ...
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
Wenn in diesem speziellen Beispiel zwei oder mehr Elemente der Menge gleich vorkommen, wird dasjenige zurückgegeben, das zuletzt im Array angezeigt wird. Es ist auch erwähnenswert, dass dadurch Ihr ursprüngliches Array geändert wird - was verhindert werden kann, wenn Sie dies Array.slice
vorher mit einem Aufruf wünschen .
Edit: das Beispiel mit einigen aktualisiert ES6 Fett Pfeile , weil 2015 passiert ist, und ich denke , sie sehen ziemlich ... Wenn Sie mit der Abwärtskompatibilität betroffen sind können Sie dies finden in der Revisionshistorie .
Auf George Jempty's
Anfrage, dass der Algorithmus Bindungen berücksichtigt, schlage ich eine modifizierte Version des Matthew Flaschen's
Algorithmus vor.
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;
}
Dies gibt nun eine Zeichenfolge mit den durch ein &
Symbol begrenzten Moduselementen zurück. Wenn das Ergebnis empfangen wird, kann es auf dieses &
Element aufgeteilt werden und Sie haben Ihre Modi.
Eine andere Möglichkeit wäre, ein Array von Moduselementen wie folgt zurückzugeben:
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;
}
Im obigen Beispiel könnten Sie dann das Ergebnis der Funktion als Array von Modi behandeln.
modes
um [array[0]]
als Anfangswert. Dadurch wird sichergestellt, dass Sie Duplikate haben modes
. Dies sollte den Trick tunvar modes = []
==
zu ändern ===
, um strikte Gleichheit durchzusetzen
Basierend auf der ES6 + -Antwort von Emissary könnten Array.prototype.reduce
Sie Ihren Vergleich durchführen (im Gegensatz zum Sortieren, Poppen und potenziellen Mutieren Ihres Arrays), was meiner Meinung nach ziemlich schick aussieht.
const mode = (myArray) =>
myArray.reduce(
(a,b,i,arr)=>
(arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b),
null)
Ich verwende standardmäßig null, was Ihnen nicht immer eine wahrheitsgemäße Antwort gibt, wenn null eine mögliche Option ist, nach der Sie filtern. Vielleicht könnte dies ein optionales zweites Argument sein
Der Nachteil ist, wie bei verschiedenen anderen Lösungen, dass es keine "Zeichnungszustände" behandelt, aber dies könnte immer noch mit einer etwas komplizierteren Reduktionsfunktion erreicht werden.
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] }
}
Hier einen deklarativen Ansatz ausprobieren. Diese Lösung erstellt ein Objekt, um die Vorkommen jedes Wortes zu erfassen. Anschließend wird das Objekt auf ein Array heruntergefiltert, indem die Gesamtvorkommen jedes Wortes mit dem höchsten im Objekt gefundenen Wert verglichen werden.
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));
Da ich diese Funktion als Quiz für die Interviewer verwende, poste ich meine Lösung:
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))
Eine weitere JS-Lösung von: https://www.w3resource.com/javascript-exercises/javascript-array-exercise-8.php
Kann das auch versuchen:
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
Hier ist eine andere ES6-Methode mit O (n) -Komplexität
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);
Zeit für eine andere Lösung:
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;
}
Wenn es auf die Kürze ankommt (nicht), dann:
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;
}
Wenn nicht vorhandene Mitglieder vermieden werden sollen (z. B. spärliches Array), ist ein zusätzlicher hasOwnProperty- Test erforderlich:
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
Andere Antworten hier werden undefiniert zurückgegeben .
Diese Lösung kann mehrere Elemente eines Arrays zurückgeben, wenn sie gleichzeitig auftreten. Beispielsweise hat ein Array arr = [3,4,3,6,4] zwei Moduswerte, 3 und 6.
Hier ist die Lösung,
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;
}
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
}
Hier ist meine Lösung für dieses Problem, aber mit Zahlen und unter Verwendung der neuen 'Set'-Funktion. Es ist nicht sehr performant, aber ich hatte definitiv viel Spaß beim Schreiben und es unterstützt mehrere Maximalwerte.
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]
Verwenden Sie dies übrigens nicht für die Produktion. Dies ist nur ein Beispiel dafür, wie Sie es nur mit ES6- und Array-Funktionen lösen können.
Hier ist meine Lösung: -
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']))
var mode = 0;
var c = 0;
var num = new Array();
var value = 0;
var greatest = 0;
var ct = 0;
Hinweis: ct ist die Länge des Arrays.
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'))
Versuchen Sie es auch, dies berücksichtigt nicht die Browserversion.
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']));
Bitte beachten Sie, dass diese Funktion das letzte Vorkommen im Array zurückgibt, wenn zwei oder mehr Einträge gleich oft erscheinen!
Hier ist die moderne Version mit integrierten Karten (sie funktioniert also nicht nur mit Dingen, die in eindeutige Zeichenfolgen konvertiert werden können):
'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']));
Ich denke, Sie haben zwei Ansätze. Beides hat Vorteile.
Sortieren Sie dann Count oder Loop Through und verwenden Sie eine Hash-Tabelle, um die Zählung für Sie durchzuführen.
Die Hashtabelle ist schön, denn wenn Sie mit der Verarbeitung fertig sind, haben Sie auch alle unterschiedlichen Elemente. Wenn Sie jedoch Millionen von Elementen hatten, könnte die Hash-Tabelle viel Speicherplatz beanspruchen, wenn die Duplizierungsrate niedrig ist. Der Ansatz "Sortieren, dann Zählen" hätte einen viel besser kontrollierbaren Speicherbedarf.
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);
Sie können dies versuchen:
// 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;
}
Sie könnten es in O (n) Komplexität lösen
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" );
Kopieren Sie einfach die Chrome-Konsole und fügen Sie sie ein, um den obigen Code auszuführen.
Diese Funktion ist eine generische Funktion für jede Art von Informationen. Es zählt das Auftreten der Elemente und gibt dann ein Array mit maximal auftretenden Elementen zurück.
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);}
Hier ist mein Weg. Ich versuche, Datenfaust zu gruppieren.
const _ = require("underscore")
var test = [ 1, 1, 2, 1 ];
var groupResult = _.groupBy(test, (e)=> e);
Das groupResult sollte sein
{
1: [1, 1, 1]
2: [2]
}
Suchen Sie dann die Eigenschaft mit dem längsten Array
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;
}
Der vollständige Code sieht aus wie
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);
Mit ES6 können Sie die Methode folgendermaßen verketten:
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']));
Wenn zwei Elemente dasselbe Vorkommen haben, werden beide zurückgegeben. Und es funktioniert mit jeder Art von Element.
arr
in einem Bereich verwenden, in dem diese Variable bereits als Parameter definiert ist. Dies kann je nach verwendetem Browser zu Fehlern führen.
arr
bezieht sich arr.indexOf(cur)
? Der oberste Parameter oder der innerhalb des Reduzierens?
Um einen wirklich einfach zu lesenden, wartbaren Code zu erhalten, teile ich Folgendes:
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]
};
}
Hoffe es hilft jemandem;)!