Szukam eleganckiego sposobu na określenie, który element ma największe wystąpienie ( tryb ) w tablicy JavaScript.
Na przykład w
['pear', 'apple', 'orange', 'apple']
'apple'
elementem jest najczęściej jeden.
Szukam eleganckiego sposobu na określenie, który element ma największe wystąpienie ( tryb ) w tablicy JavaScript.
Na przykład w
['pear', 'apple', 'orange', 'apple']
'apple'
elementem jest najczęściej jeden.
Odpowiedzi:
To tylko tryb. Oto szybkie, niezoptymalizowane rozwiązanie. Powinno być 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;
}
Od 2009 roku nastąpił rozwój javascript - pomyślałem, że dodam inną opcję. Mniej przejmuję się wydajnością, dopóki faktycznie nie stanowi to problemu, więc moja definicja „eleganckiego” kodu (zgodnie z zaleceniami OP) sprzyja czytelności - co jest oczywiście subiektywne ...
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
W tym konkretnym przykładzie, jeśli dwa lub więcej elementów zestawu ma równe wystąpienia, zostanie zwrócony ten, który pojawia się jako ostatni w tablicy. Warto również zauważyć, że zmodyfikuje to twoją oryginalną tablicę - czemu można zapobiec, jeśli chcesz, Array.slice
wcześniej wykonując połączenie.
Edycja: zaktualizowałem przykład kilkoma grubymi strzałkami ES6, ponieważ wydarzył się rok 2015 i myślę, że wyglądają ładnie ... Jeśli obawiasz się kompatybilności wstecznej, możesz to znaleźć w historii wersji .
Jak na George Jempty's
prośbą o uwzględnienie powiązań algorytmu proponuję zmodyfikowaną wersję Matthew Flaschen's
algorytmu.
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;
}
To teraz zwróci ciąg z elementami trybu oddzielonymi znakiem &
symbolem. Po otrzymaniu wyniku można go podzielić na ten &
element i masz swój tryb (y).
Inną opcją byłoby zwrócenie tablicy elementów trybu w następujący sposób:
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;
}
W powyższym przykładzie byłbyś wtedy w stanie obsłużyć wynik funkcji jako tablicę trybów.
modes
, aby [array[0]]
jako wartości początkowej. Zapewni to, że masz duplikaty w modes
. To powinno załatwić var modes = []
==
na, ===
aby wymusić ścisłą równość
Opierając się na odpowiedzi Emissary z ES6 +, możesz użyć Array.prototype.reduce
do porównania (w przeciwieństwie do sortowania, wyskakiwania i potencjalnej mutacji tablicy), które moim zdaniem wygląda całkiem sprytnie.
const mode = (myArray) =>
myArray.reduce(
(a,b,i,arr)=>
(arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b),
null)
Domyślnie jestem na null, co nie zawsze da ci prawdziwą odpowiedź, jeśli null jest możliwą opcją, według której filtrujesz, może to być opcjonalny drugi argument
Wadą, podobnie jak w przypadku różnych innych rozwiązań, jest to, że nie obsługuje on „stanów rysowania”, ale nadal można to osiągnąć przy nieco bardziej zaangażowanej funkcji redukcji.
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] }
}
Ponieważ używam tej funkcji jako quizu dla ankieterów, publikuję moje rozwiązanie:
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))
Wypróbowuję tutaj podejście deklaratywne. To rozwiązanie tworzy obiekt, który zlicza wystąpienia każdego słowa. Następnie filtruje obiekt do tablicy, porównując całkowitą liczbę wystąpień każdego słowa z najwyższą wartością znalezioną w obiekcie.
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));
Czas na inne rozwiązanie:
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;
}
Jeśli zwięzłość ma znaczenie (nie ma), to:
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;
}
Jeśli chcesz uniknąć nieistniejących elementów (np. Rzadkiej tablicy), wymagany jest dodatkowy test 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
Inne odpowiedzi tutaj zwrócą wartość niezdefiniowaną .
Kolejne rozwiązanie JS z: https://www.w3resource.com/javascript-exercises/javascript-array-exercise-8.php
Możesz też tego spróbować:
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
Oto inny sposób w ES6 na zrobienie tego ze złożonością 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
}
Oto moje rozwiązanie tego problemu, ale z liczbami i nową funkcją „Ustaw”. Nie jest zbyt wydajny, ale zdecydowanie dobrze się bawiłem, pisząc to i obsługuje wiele maksymalnych wartości.
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]
Nawiasem mówiąc, nie używaj tego do produkcji, to tylko ilustracja tego, jak można to rozwiązać za pomocą tylko funkcji ES6 i Array.
Oto moje rozwiązanie: -
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']))
Ze względu na naprawdę łatwy do odczytania i łatwego w utrzymaniu kod udostępniam to:
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]
};
}
Mam nadzieję, że to komuś pomoże;)!
To rozwiązanie może zwrócić wiele elementów tablicy w przypadku remisu. Na przykład tablica
arr = [ 3, 4, 3, 6, 4, ];
ma dwie wartości trybu: 3
i 6
.
Oto rozwiązanie.
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;
Uwaga: ct to długość tablicy.
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'))
Spróbuj też, to nie dotyczy wersji przeglądarki konta.
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']));
Zwróć uwagę, że ta funkcja zwraca ostatnie wystąpienie w tablicy, gdy 2 lub więcej wpisów pojawia się tyle samo razy!
Oto nowoczesna wersja wykorzystująca wbudowane mapy (więc działa nie tylko na rzeczach, które można przekonwertować na unikalne ciągi):
'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']));
Myślę, że masz dwa podejścia. Oba mają zalety.
Sortuj, a następnie Policz lub Zapętlaj i użyj tabeli skrótów, aby policzyć za Ciebie.
Tablica hashy jest fajna, ponieważ po zakończeniu przetwarzania masz również wszystkie odrębne elementy. Gdybyś miał jednak miliony elementów, tabela skrótów mogłaby zająć dużo pamięci, jeśli współczynnik powielania jest niski. Metoda sortowania, a następnie liczenia miałaby znacznie bardziej kontrolowany ślad pamięci.
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);
Możesz spróbować tego:
// 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;
}
Możesz rozwiązać to w złożoności 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" );
Po prostu skopiuj i wklej w konsoli chrome, aby uruchomić powyższy kod.
Ta funkcja jest funkcją ogólną dla każdego typu informacji. Zlicza wystąpienia elementów, a następnie zwraca tablicę z maksymalną liczbą występujących elementów.
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);}
Oto moja droga. Próbuję grupować dane.
const _ = require("underscore")
var test = [ 1, 1, 2, 1 ];
var groupResult = _.groupBy(test, (e)=> e);
Wynik groupResult powinien być
{
1: [1, 1, 1]
2: [2]
}
Następnie znajdź właściwość, która ma najdłuższą tablicę
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;
}
Wygląda jak cały kod
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);
W ES6 możesz połączyć metodę w następujący sposób:
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']));
Jeśli dwa elementy mają to samo wystąpienie, zwróci oba z nich. Działa z każdym rodzajem elementu.
arr
w zakresie, w którym ta zmienna jest już zdefiniowana jako parametr. Może to prowadzić do błędów w zależności od używanej przeglądarki.
arr
jest określony arr.indexOf(cur)
? Górny parametr, czy ten wewnątrz redukuj ??