Поиск и подсчет одинаковых значений массива (js)

127
25 января 2020, 05:10

Всем привет! Имеется массив

var arr=["aa","aa","ab","ab","ac","a","s",]; 
 
Подскажите пожалуйста, как подсчитать одинаковое количество элементов и вывести в массив в виде array [ aa:3, ab:2 , ac:1, a:1, s:1 ]. В интернете нашел решение в виде

var arr = ["aa", "aa", "ab", "ab", "ac", "a", "s", ]; 
 
var arr2 = []; 
for (i in arr) { 
  if (arr2[arr[i]] != undefined) { 
    (arr2[arr[i]] ++) 
  } else { 
    (arr2[arr[i]] = 1) 
  } 
} 
console.log(arr2);
Но вся сложность в том, что в arr2 значения выводятся не в отдельный элемент массива, а в один. Из-за этого я не могу применить arr.sort() для того, чтобы отсортировать по количеству повторений. Если кто-то может помочь, буду ооочень рад!

Answer 1

Функция sort может принимать функцию сравнения, в которой как раз и можно сравнивать количество повторений, а не зами элементы.

Кроме того, так как в массив добавляются нечисловые ключи, можно обойтись без второго массива:

for (var len = arr.length, i = len; --i >= 0;) {
  if (arr[arr[i]]) {
    arr[arr[i]] += 1;
    arr.splice(i, 1);
  } else {
    arr[arr[i]] = 1;
  }
}

Так как добавленные свойства не числовые, они не участвуют в сортировке, но к ним можно обращаться в функции сравнения:

arr.sort(function(a, b) {
  return arr[b] - arr[a];
});

Для вывода можно воспользоваться несколькими путями: например, получить новый массив с элементами в которых будут поля соответствующие и элементу, и количеству его повторений. Либо воспользоваться функцией JSON.stringify

Пример:

var arr = ["aa", "aa", "ab", "ab", "ac", "a", "s"]; 
 
for (var len = arr.length, i = len; --i >= 0;) { 
  if (arr[arr[i]]) { 
    arr[arr[i]] += 1; 
    arr.splice(i, 1); 
  } else { 
    arr[arr[i]] = 1; 
  } 
} 
arr.sort(function(a, b) { 
  return arr[b] - arr[a]; 
}); 
 
console.log(arr); 
var stringResult = JSON.stringify(arr, function(k, v) { 
  if (k == '') return v; 
  return `${v} - ${arr[v]}`; 
}, 2); 
document.getElementById('result').innerHTML = stringResult; 
console.log(stringResult); 
console.log(arr.map((el, i, a) => ({ 
  [el]: a[el] 
})));
<pre id="result"></pre>

Чтобы не работать с массивом как с объектами можно воспользоваться функцией reduce и сразу получить массив, который можно будет отсортировать.

var arr = ["aa", "aa", "ab", "ab", "ac", "a", "s", "s", "s"]; 
 
var resultReduce = arr.reduce(function(acc, cur) { 
  if (!acc.hash[cur]) { 
    acc.hash[cur] = { [cur]: 1 }; 
    acc.map.set(acc.hash[cur], 1); 
    acc.result.push(acc.hash[cur]); 
  } else { 
    acc.hash[cur][cur] += 1; 
    acc.map.set(acc.hash[cur], acc.hash[cur][cur]); 
  } 
  return acc; 
}, { 
  hash: {}, 
  map: new Map(), 
  result: [] 
}); 
 
var result = resultReduce.result.sort(function(a, b) { 
  return resultReduce.map.get(b) - resultReduce.map.get(a); 
}); 
 
console.log(result);

Answer 2

вот вам два решения - второе использует es6 структуру Map, первое довольно банальное.

А для сортировки нужно получить массив, например вот такого вида

[{arrayItem: aa, count: 2}, {arrayItem: ab, count: 2}, ...]

чтобы была возможность отсортировать эти элементы по полю count, а индексы должны быть целочисленными, у вас они строковые, потому и не отсортировать их.

var arr = ["aa", "aa", "ab", "ab", "ac", "a", "s", "s", "s"]; 
 
function getCountsSorted_1(arr) { 
    var counts = []; 
    var res = []; 
 
    for (var i in arr) { 
        if (counts[arr[i]]) { 
            (counts[arr[i]]++); 
        } else { 
            (counts[arr[i]] = 1) 
        } 
    } 
 
    var j = 0; 
    for (var i in counts) { 
        res[j++] = { 
            arrayItem: i, 
            count: counts[i] 
        }; 
    } 
 
    return res.sort(function(a, b) { 
        return a.count < b.count; 
    }).map(function(entry) { 
        var ret = {}; 
        ret[entry.arrayItem] = entry.count; 
        return ret; 
    }); 
} 
 
function getCountsSorted_2(arr) { 
    var counts = new Map(); 
 
    for (var i in arr) { 
        if (counts.has(arr[i])) { 
            counts.set(arr[i], counts.get(arr[i]) + 1); 
        } else { 
            counts.set(arr[i], 1); 
        } 
    } 
 
    return Array.from(counts).sort(function(a, b) { 
        return a[1] < b[1]; 
    }).map(function(entry) { 
        var ret = {}; 
        ret[entry[0]] = entry[1]; 
        return ret; 
    }); 
} 
 
 
console.log(getCountsSorted_1(arr)); 
console.log(getCountsSorted_2(arr));

Answer 3

var arr = ["aa", "aa", "ab", "ab", "ab", "ac", "a", "s", ]; 
var arr2 = {}; 
var arr3 = {}; 
 
for (var i = 0; i < arr.length; i++) { 
  if (arr2[arr[i]]) { 
    arr2[arr[i]] += 1; 
  } else { 
    arr2[arr[i]] = 1; 
  } 
} 
console.log(arr2); 
 
var forsort = []; 
for (var item in arr2) 
  forsort.push([item, arr2[item]]) 
forsort.sort( 
  function(a, b) { 
    return b[1] - a[1] 
  }) 
for (var z = 0; z < forsort.length; z++) { 
  arr3[forsort[z][0]] = forsort[z][1]; 
} 
console.log(arr3);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<span id="arr1"></span>

Answer 4

В итоге рабочий код:

var arr = ["aa", "aa", "ab", "ab", "ac", "a", "s", "s", "s"]; 
 
var resultReduce = arr.reduce(function(acc, cur) { 
  if (!acc.hash[cur]) { 
    acc.hash[cur] = { [cur]: 1 }; 
    acc.map.set(acc.hash[cur], 1); 
    acc.result.push(acc.hash[cur]); 
  } else { 
    acc.hash[cur][cur] += 1; 
    acc.map.set(acc.hash[cur], acc.hash[cur][cur]); 
  } 
  return acc; 
}, { 
  hash: {}, 
  map: new Map(), 
  result: [] 
}); 
 
var result = resultReduce.result.sort(function(a, b) { 
  return resultReduce.map.get(b) - resultReduce.map.get(a); 
}); 
 
console.log(result);

Но теперь надо, чтобы результат выводился в любое место на экран с указанием количества повторов. У меня получается выводить только сами значений массива, кол-во почему-то не выводится?

Answer 5

var arr = ["aa", "aa", "ab", "ab", "ac", "a", "s"], 
    counts = {}, 
    res = []; 
for (var i in arr) { 
    counts[arr[i]] = (counts[arr[i]] || 0) + 1; 
} 
Object.keys(counts).sort(function(a, b) { 
    return counts[b] - counts[a] 
}).forEach(function(el, idx, arr) { 
    res.push([el, counts[el]]); 
}); 
console.log(res);

READ ALSO
Изменение jsf страницы из другой страницы

Изменение jsf страницы из другой страницы

Хочу по нажатию на ссылку на одной странице, изменить элемент другой страницы(изменить тэг) и что-бы это было real time, подскажите как можно это...

140
Добавление блока при нажатии на кнопку

Добавление блока при нажатии на кнопку

Как сделать, чтобы при нажатии на кнопку появлялся еще один такой блок

141
Есть проблема запуска этого кода на c# и oracle

Есть проблема запуска этого кода на c# и oracle

выходит ошибка OracleManagedDataAccess

153