JavaScript配列で最も出現頻度の高い要素(モード)を判別するための洗練された方法を探しています。
たとえば、
['pear', 'apple', 'orange', 'apple']
要素は'apple'
最も頻繁なものです。
JavaScript配列で最も出現頻度の高い要素(モード)を判別するための洗練された方法を探しています。
たとえば、
['pear', 'apple', 'orange', 'apple']
要素は'apple'
最も頻繁なものです。
モードはこれだけです。これは、最適化されていない簡単なソリューションです。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
この特定の例では、セットの 2 つ以上の要素の出現回数が等しい場合、配列内で最後に表示される要素が返されます。また、元の配列が変更されることにも注意してください 。これは、Array.slice
事前に呼び出しを行うことで防ぐことができます。
編集: 2015が発生したため、いくつかのES6 太い矢印で例を更新しました。見た目はきれいだと思います...後方互換性が心配な場合は、改訂履歴でこれを見つけることができます。
アルゴリズムに同点を考慮させるという要求に従って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;
}
上記の例では、関数の結果をモードの配列として処理できるようになります。
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 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));
これは、O(n) の複雑さでそれを行う別の ES6 の方法です。
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 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を返します。
これがこの問題に対する私の解決策ですが、数字と新しい「セット」機能を使用しています。パフォーマンスはそれほど高くありませんが、これを書くのは間違いなくとても楽しかったし、複数の最大値をサポートしています。
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 と配列関数のみで解決する方法の単なる例です。
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 arr = [
2, 1, 10, 7, 10, 3, 10, 8, 7, 3, 10, 5, 4, 6, 7, 9, 2, 2, 2, 6, 3, 7, 6, 9, 8,
9, 10, 8, 8, 8, 4, 1, 9, 3, 4, 5, 8, 1, 9, 3, 2, 8, 1, 9, 6, 3, 9, 2, 3, 5, 3,
2, 7, 2, 5, 4, 5, 5, 8, 4, 6, 3, 9, 2, 3, 3, 10, 3, 3, 1, 4, 5, 4, 1, 5, 9, 6,
2, 3, 10, 9, 4, 3, 4, 5, 7, 2, 7, 2, 9, 8, 1, 8, 3, 3, 3, 3, 1, 1, 3,
];
function max(arr) {
let newObj = {};
arr.forEach((d, i) => {
if (newObj[d] != undefined) {
++newObj[d];
} else {
newObj[d] = 0;
}
});
let nwres = {};
for (let maxItem in newObj) {
if (newObj[maxItem] == Math.max(...Object.values(newObj))) {
nwres[maxItem] = newObj[maxItem];
}
}
return nwres;
}
console.log(max(arr));
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 () {
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;
}
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" );
上記のコードを実行するには、Chrome コンソールにコピー アンド ペーストするだけです。
2つのアプローチがあると思います。どちらにも利点があります。
並べ替えてからカウントするか、ループスルーして、ハッシュテーブルを使用してカウントを行います。
処理が完了すると、すべての個別の要素も得られるため、ハッシュテーブルは便利です。ただし、何百万ものアイテムがある場合、重複率が低いと、ハッシュ テーブルが大量のメモリを使用することになります。並べ替えてからカウントするアプローチでは、より制御可能なメモリ フットプリントが得られます。
試みることができます :
var arr = [10,3,4,5,3,4,3,8,3,6,3,5,1];
var temp = {};
for(let i=0;i<arr.length;i++){
if(temp[arr[i]]==undefined){
temp[arr[i]]=1;
}else{
temp[arr[i]]+=1;
}
}
var max=0, maxEle;
for(const i in temp){
if(temp[i]>max){
max = temp[i];
maxEle=i;
}
}
console.log(`most occurred element is ${maxEle} and number of times is ${max}`);`
これを試すことができます:
// 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;
}
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']));
2 つの要素に同じ出現箇所がある場合は、両方が返されます。また、あらゆるタイプの要素で機能します。