Я пытаюсь написать функцию, которая перебирает список строк и возвращает 10 наиболее часто встречающихся строк в списке. Я пытаюсь придумать несколько решений этого вопроса
Вот мое первое решение
const list = [
"this",
"is",
"a",
"test",
"which",
"word",
"wins",
"top",
"i",
"don't",
"know",
"off",
"hand",
"do",
"you",
"this",
"a",
"a",
"this",
"test",
"a",
"a",
"do",
"hand",
"hand",
"a",
"whatever",
"what",
"do",
"do"
];
function fn1(strArr) {
const map = new Map()
for(const str of strArr) {
if (map.has(str)) {
map.set(str, map.get(str) + 1)
} else {
map.set(str, 1)
}
}
const sortedMap =[...map.entries()].sort(([_,a], [__,b]) => a < b ? 1 : -1)
return sortedMap.slice(0 , 10).map(([str]) => str)
}
Но я не могу найти других решений этого вопроса. Может ли кто-нибудь предложить альтернативное предложение?
Кроме того, следует отметить, что список может быть очень большим, может содержать 1 миллион строк. Поэтому нам нужно попытаться свести к минимуму сложность времени выполнения.
.sort()
отчасти не нужен и может иметь верхнюю границу O(n log n)
, но, поскольку вам нужны только 10 лучших, почему бы не перебрать его один раз, чтобы сохранить его на уровне O(n)
. Я думаю, что ваш начальный цикл for уже O(n)
. Если это в каком-то производственном приложении, возможно, также запустите веб-работника, чтобы уменьшить массив вдвое.
Я думаю, что это (способ map/dict) лучший подход. Вы можете сделать это намного проще с помощью cnt = {}; for(const s of strArr) cnt[s] ? ++cnt[s] : cnt[s]=1;
Другой, но, вероятно, не лучший подход может состоять в том, чтобы отсортировать массив, а затем подсчитать последовательные идентичные записи и обновить список из 10 самых высоких частот. Вы можете найти много похожих записей с помощью поиска Google по запросу «количество вхождений javascript ...».
@ t348575 Я не думаю, что ваше предложение равно O (n), потому что для каждого элемента поиск счетчика для этой строки в словаре счетчиков в среднем составляет O (log n). Я думаю, что все эти методы - O (n log n).
@Max Я думаю, что ecmascript предписывает .has
и другим функциям карты быть на уровне или ниже O(n)
@ t348575 Да, конечно, .has равно o (n), как я уже сказал, это O (log n) (^), но выполнение этого для каждого члена дает O (n log n). (^: Здесь n — количество уже сохраненных записей, но это не меняет асимптотику, поскольку вы можете забыть о первой половине и рассматривать только вторую половину обработки массива (от индексов n/2 до n) и положить n /2 везде, чтобы получить нижнюю границу.Кроме того, учитывая повторения, общее количество записей будет меньше n в какой-то раз, но это также не должно изменить порядок сложности.)
это хорошая проблема для уменьшения карты. :-)
const list = [
"this",
"is",
"a",
"test",
"which",
"word",
"wins",
"top",
"i",
"don't",
"know",
"off",
"hand",
"do",
"you",
"this",
"a",
"a",
"this",
"test",
"a",
"a",
"do",
"hand",
"hand",
"a",
"whatever",
"what",
"do",
"do"
];
const counts = list.reduce((a, c) => {
a[c] = (a[c] || 0) + 1;
return a;
}, {})
const items = Object.keys(counts).map(k => {
return {
word: k,
count: counts[k]
};
});
items.sort((a, b) => a.count > b.count ? -1 : 1);
const result = items.slice(0, 10).map(item => item.word);
console.info(result);
Честно говоря, я не понимаю, чем это отличается от решения, которое я представил в описании. Конечно, вы используете сокращение. Но оба решения отсортировали массив, что усложняет выполнение nlogn.
Попробуй это:
const list = [
"this",
"is",
"a",
"test",
"which",
"word",
"wins",
"top",
"i",
"don't",
"know",
"off",
"hand",
"do",
"you",
"this",
"a",
"a",
"this",
"test",
"a",
"a",
"do",
"hand",
"hand",
"a",
"whatever",
"what",
"do",
"do"
];
let counter = {}
for (let item of list){
counter[item] = 1 + (counter[item] || 0)
}
console.info(counter);
let result = [];
let entries = Object.entries(counter);
let sorted = entries.sort((a, b) => b[1] - a[1]);
for(let i = 0; i < 10; i++){
result.push(sorted[i][0])
}
console.info(result)
Честно говоря, я не понимаю, чем это отличается от решения, которое я представил в описании.
const list = [
"this",
"is",
"a",
"test",
"which",
"word",
"wins",
"top",
.
.
.
"do",
"do"
];
const newObjectArray = {};
list.forEach(item=>{
newObjectArray[item]? newObjectArray[item]++: newObjectArray[item] = 1
});
// now sort based on the newObjectArray values and return the first 10
это newObjectArray
массив или объект?
это объект {}
Это точно такой же подход, как и у ОП.
Я думаю, что мы можем сделать следующие шаги для больших данных:
Вот код:
const list = [
"this",
"is",
"a",
"test",
"which",
"word",
"wins",
"top",
"i",
"don't",
"know",
"off",
"hand",
"do",
"you",
"this",
"a",
"a",
"this",
"test",
"a",
"a",
"do",
"hand",
"hand",
"a",
"whatever",
"what",
"do",
"do"
];
// mock 1 million data;
for (let i = 0; i < 1000000; i++) {
list.push('a');
}
console.clear();
let resultsmap = new Map();
// Object to map with frequent times
function toMap() {
for (let i = 0; i < list.length; i++) {
let item = list[i];
if (resultsmap.has(item)) {
let count = resultsmap.get(item);
resultsmap.set(item, count + 1);
} else {
resultsmap.set(item, 1);
}
}
}
// Found the top 1 for current map
function top1() {
let maxCount = 0;
let keyOfMaxCount = '';
resultsmap.forEach((value, key) => {
if (maxCount < value) {
maxCount = value;
keyOfMaxCount = key;
}
});
return { key: keyOfMaxCount, value: maxCount };
}
toMap();
for(let i=0; i< 10; i++) {
let topObj = top1();
console.info(topObj);
resultsmap.delete(topObj.key);
}
Могу я спросить, почему вы используете некоторые функции ES6, такие как map
и forEach
, но все еще используете var
вместо const
или let
?
Я пытаюсь не использовать ES6 и использовать пару ключ-значение объекта вместо Map, но это очень утомительно, поэтому замените Map и некоторые функции ES6 и забыли пересмотреть ключевое слово var. Извини за это.
Просто замените все var
на let
.
Для этого есть два подхода, причем первый (простая сортировка) уже реализован самостоятельно. Сложность времени: O (N log N), поскольку вы переопределяете весь массив N раз, а затем сортируете N элементов, которые занимают N log N раз. Космическая сложность: O(N)
Второй подход будет заключаться в использовании кучи счетчиков (очередь с минимальным приоритетом, которая сначала выталкивает наименьшие счетчики), после каждой вставки мы проверяем, что, если размер кучи больше 10, мы выталкиваем последний 1, а затем вместо сортируя, мы просто выталкиваем последние 10 элементов. Временная сложность: O (N log k), где N — длина списка, а K — самые верхние строки, в вашем случае это 10. Это потому, что мы следим за тем, чтобы размер кучи не превышал K и с каждым вставить в кучу, он сортирует себя за время O (log K), что дает нам O (N log k) общей временной сложности. Космическая сложность: O(N)
Пример:
const list = [
"this",
"is",
"a",
...
"do"
];
const counts = {};
list.forEach(item=>{
counts[item]? counts[item]++: counts[item] = 1;
});
// Now that counts is a map of {word -> count}, we need to add these into a priority queue and just pop.
// I will not be implementing a priority queue in this example, you can probably just find an npm package that implements it in a much more efficient way.
const priorityQueue = new PriorityQueue((a,b) => a.count - b.count); // you usually need to pass a comparator function
Object.entries(counts).forEach(([word, count]) => {
priorityQueue.offer({word, count});
if (priorityQueue.size() > 10)
priorityQueue.pop();
}};
// now, just pop the first K (10) elements from the PriorityQueue:
for(let i=0; i<10; i++) {
console.info(priorityQueue.pop())
}
«Это потому, что при каждой вставке в кучу он сортируется за время O (log K)». Я не думаю, что это правильно. Глядя на код, я могу сказать, что размер кучи может достигать N, а вставка в дерево кучи с N узлами стоит O(logN) времени.
@yemre вы правы, я забыл, что важной частью подхода было использование очереди с минимальным приоритетом вместо максимального. Я отредактировал пример кода и объяснение, теперь он должен работать с фактическим O (N log K)
(Когда и где речь идет об одном и том же, пожалуйста, не чередуйте прописные и строчные буквы, как kK выше. (Если вообще используйте одинаковые буквы в разных регистрах для достаточно связанных величин.))
Я думаю, что временная сложность для первого подхода, т.е. подход, который я написал в описании, не O (nlogn), а O (n + klogk), где n — общее количество строк, а k — количество уникальных строк, поскольку вы только сортировка ключей хэш-карты.
Вот решение, которое позволяет избежать сортировки, собирая записи количества слов Map()
в объекте по значению количества. Результатом будут последние 10 элементов в Object.entries()
этого объекта. Следует отметить, что это основано на упорядочении объектных ключей, которое исторически было занижено, но, особенно для целочисленных ключей, используемых здесь, предлагает предсказуемое восходящее упорядочение в соответствии с обновлениями спецификации. – см.: Вводит ли ES6 четко определенный порядок перечисления свойств объекта?
Это решение имеет дополнительное преимущество, заключающееся в том, что оно возвращает массивы слов с одинаковым количеством, а не произвольное отсечение, которое вводят решения, использующие sort()
.
const input = [ "this", "is", "a", "test", "which", "word", "wins", "top", "i", "don't", "know", "off", "hand", "do", "you", "this", "a", "a", "this", "test", "a", "a", "do", "hand", "hand", "a", "whatever", "what", "do", "do"];
let counts = new Map(), i;
for (i = 0; i < input.length; i++) {
counts.set(input[i], (counts.get(input[i]) ?? 0) + 1);
}
let countHash = {};
counts.forEach((count, word) => (countHash[count] ??= []).push(word));
let result = Object.entries(countHash);
if (result.length > 10) result = result.slice(result.length - 10);
// output
for (let j = result.length - 1; j >= 0; j--) {
console.info(JSON.stringify(result[j]));
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
Чтобы избежать неопределенности упорядочения/сложности сортировки объекта, используемого для хеширования счетчиков Map с использованием значения счетчика в качестве ключа, вместо этого можно использовать разреженный массив, просто заменив назначение объекта на назначение массива и используя значение счетчика в качестве индекса.
let countArr = [];
counts.forEach((count, word) => (countArr[count] ??= []).push(word));
Object.entries()
, вызванный для разреженного массива, учитывает дыры и возвращает только существующие [key, value]
пары. (Это верно для Object.keys()
, а также для итерации с использованием for...in
).
const input = [ "this", "is", "a", "test", "which", "word", "wins", "top", "i", "don't", "know", "off", "hand", "do", "you", "this", "a", "a", "this", "test", "a", "a", "do", "hand", "hand", "a", "whatever", "what", "do", "do"];
let counts = new Map(), i;
for (i = 0; i < input.length; i++) {
counts.set(input[i], (counts.get(input[i]) ?? 0) + 1);
}
let countArr = [];
counts.forEach((count, word) => (countArr[count] ??= []).push(word));
let result = Object.entries(countArr);
if (result.length > 10) result = result.slice(result.length - 10);
// output
for (let j = result.length - 1; j >= 0; j--) {
console.info(JSON.stringify(result[j]));
}
// Output of this answer
[
[6, ['a']],
[4, ['do']],
[3, ['this', 'hand']],
[2, ['test']],
[1, ['is', 'which', 'word', 'wins', 'top', 'i', "don't", 'know', 'off', 'you', 'whatever', 'what']]
]
// Output using sort
[
[6, 'a'],
[4, 'do'],
[3, 'this'],
[3, 'hand'],
[2, 'test'],
[1, 'is'],
[1, 'which'],
[1, 'word'],
[1, 'wins'],
[1, 'top']
]
// [ 1, 'i' ],
// [ 1, "don't" ],
// [ 1, 'know' ],
// [ 1, 'off' ],
// [ 1, 'you' ],
// [ 1, 'whatever' ],
// [ 1, 'what' ]
это интересно. Таким образом, он основан на том факте, что объекты JS с целочисленным ключом будут автоматически сортировать их по возрастанию...
Точно (можно также использовать разреженный массив со счетчиками в качестве индексов для того же конца, хотя я нашел его менее эффективным). В целом это оставляет вам решение O (n) (начальное сопоставление точно, и в худшем случае, если все слова уникальны, хеширование счетчика и вызов Object.entries, но они, скорее всего, меньше из-за группировки).
извините, как это все еще O (n)? сортировка целочисленного ключа все еще имеет сложность времени выполнения O (nlogn), верно? Кроме того, «разреженный массив со счетчиками в виде индексов на одном конце» звучит для меня довольно интересно. не могли бы вы добавить это в качестве альтернативы вопросу?
Из того, что я могу понять, Object.keys() имеет сложность O (n) Object.keys()? и целые ключи не обрабатываются так же, как именованные ключи ( v8.dev/blog/fast-properties) и сильно оптимизированы, поэтому, хотя могут быть некоторые затраты, я не верю, что это приближается к O(nlogn ). Я снова рассмотрю вариант разреженного массива.
Добавлен фрагмент разреженного массива. На самом деле это просто вопрос объявления массива вместо объекта. Провел еще несколько тестов, и он более эффективен, чем фрагмент объекта, который я опубликовал первым.
Я понимаю, что Object.keys
— это линейная сложность, поскольку она должна просто перебирать ключи. Однако, поскольку объект сортирует целочисленные ключи автоматически, моя интуиция подсказывает, что сортировка — это процесс O(nlogn). Также мне интересно, можете ли вы реализовать countHash
как Map
вместо простого объекта? Думаю, Map
тоже ведет себя как Object?
Map()
упорядочивается по порядку вставки и поддерживает его посредством преобразования, поэтому не работает. Я думаю, что разреженный массив является самым чистым (и наиболее производительным при тестировании) со встроенным неявным упорядочением.
Спасибо. Кстати, где вы нашли онлайн-редактор, который поддерживает последний синтаксис js, такой как ??=
В основном я редактирую локально (запуск node v15.4.0 в vscode), но все консоли firefox/safari/chrome поддерживают его (и фрагменты здесь). Только что попробовал jsfiddle, jsbin и stackblitz, и все они тоже, хотя codeandbox выдает ошибку.
@pilchard Проголосовал за, я действительно изо всех сил старался найти лучшее решение, чем ваше, с учетом производительности, но не смог. Я сравнил все решения во всех ответах здесь, и ваше решение было лучшим. Единственное улучшение, которое вы можете сделать, заключается в том, что в for (i = 0; i < input.length; i++)
Для каждой итерации цикла JavaScript извлекает input.length
, операции поиска ключа в каждом цикле. Нет причин, по которым этого не должно быть: for (i = 0, n = input.length; i < n; i++)
Спасибо за отзыв @Abbas, и я согласен с вашей настройкой. Оплошность с моей стороны.
@Joji Нет гарантии, что вставка пары ключ-значение в объект будет O (1), а получение keys()
- O (n). На самом деле, поскольку никакой движок JavaScript не может творить чудеса, в какой-то момент он должен быть O(n log n), когда вы можете использовать его для сортировки. Детали зависят от конкретного двигателя, количества и распределения ключей. См. этот ответ и обсуждение под ним: stackoverflow.com/a/64912755/689923
Получение карты строк и их вхождений из списка строк кажется мне легкой задачей, но поскольку вы попросили альтернативное решение, вот одно из них. Я не знаю, хороший ли это, хотя так предостережение emtor.
Предполагая, что list
такой же, как в вашем примере, превратите его в массивную строку:
const search = list.join(' ');
Почему? Потому что тогда вы можете подсчитывать вхождения с помощью RegExp#match
, например,
search.match(/\bhand\b/g).length;
//=> 3
Конечно, регулярное выражение должно быть построено динамически. Мы сделаем это позже.
Затем превратите list
в уникальный список:
const uniq_list = [...new Set(list)];
Затем вы можете отсортировать uniq_list
, подсчитав, сколько раз каждый элемент появляется в search
:
const ordered_by_occurrence =
uniq_list.sort((a, b) => {
const count_a = search.match(new RegExp(`\\b${a}\\b`, 'g')).length;
const count_b = search.match(new RegExp(`\\b${b}\\b`, 'g')).length;
return count_a >= count_b ? -1 : 1;
});
(Возврат первых n элементов упорядоченного списка тривиален.)
У меня возник соблазн понизить голосование, но вы правы, ОП просто попросил альтернативные, а не хорошие решения. Ваше решение, безусловно, креативное, и трудно придумать еще более неэффективное. ;)
Я считаю, что следующее решение является самым быстрым на практике:
n
с их частотами, как вы уже сделали. O(n)
O(n)
⌊n/2⌋ - 1
до 0). O(n)
k
раз. (В вашем случае k=10
.) O(k log n)
(Я не привожу здесь никакого кода, потому что он в основном состоит из вызова библиотеки двоичной кучи (см. здесь высокооптимизированную реализацию).)
Асимптотическая сложность равна O(n + k log n)
, что меньше O(n log k)
решения, предоставленного Chaos Monkey. Для маленьких k
(например, 10), вероятно, не будет существенной разницы. Разница становится более очевидной для больших k
(пока k ≪ n
; для гораздо больших k
см. «Альтернатива» ниже). Также обратите внимание, что постоянный коэффициент для шагов 1 и 2 равен 1, а постоянный коэффициент для шага 3 также в среднем мал (1,8814), поэтому общий постоянный коэффициент меньше 4.
Существует решение, которое решает задачу в O(n)
в среднем, также с небольшим постоянным множителем, что гораздо эффективнее при больших k
(т.е. когда k
приближается к n/2
). Недостатком является то, что (очень маловероятно) сложность в худшем случае равна O(n²)
:
n
с их частотами, как вы уже сделали. O(n)
O(n)
k
-ю по величине частоту. Все элементы слева еще больше, поэтому в результате получаются первые k
элементы массива Quickselected. O(n)
среднее, O(n²)
худшее.Можно реализовать вариант Quickselect с гарантированной O(n)
сложностью, используя медиану медиан опорного выбора, но на практике это не очень хорошо, потому что постоянный коэффициент довольно высок. Но с академической точки зрения это было бы асимптотически оптимальным решением.
Быстрый и грязный тест с n = 10^6
, k = 10
, измеряющий только время выполнения после шага 2 (поскольку шаги 1/2 являются общими для всех 5 методов):
Average time for Sort: 7.5 ms
Average time for ChaosMonkey: 10.25 ms
Average time for CountingSort: 5.25 ms
Average time for Mo B. Max-Heap: 4 ms
Average time for Mo B. Alternative (Quickselect): 3.25 ms
https://dotnetfiddle.net/oHRMsp
Мой вывод состоит в том, что для заданных параметров между разными методами нет большой разницы. Для простоты я бы просто придерживался метода сортировки, который также хорошо масштабируется как для n
, так и для k
.
(Много предостережений: он написан (неряшливо) на C#, а не на JavaScript; он не проверялся на корректность; отдельные методы не оптимизированы; время выполнения также может зависеть от распределения частот, реализованный Quickselect наивен в том, что он не оптимизирован для (здесь) распространенного случая, когда множество частот равны и т. д...)
Все проверенные методы используют дополнительное пространство O(n)
, потому что они сначала создают карту частот (а метод сортировки подсчетом использует дополнительное пространство O(n)
для наихудшего случая поверх карты частот для подсчета). Задачу можно решить всего за O(1)
дополнительного места, но за счет временной сложности O(kn²)
.
Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат.
const list = [
"this",
"is",
"a",
"test",
"which",
"word",
"wins",
"top",
"i",
"don't",
"know",
"off",
"hand",
"do",
"you",
"this",
"a",
"a",
"this",
"test",
"a",
"a",
"do",
"hand",
"hand",
"a",
"whatever",
"what",
"do",
"do"
];
function fn2(){
const sorted = list.sort((a, b) => a < b ? -1 : 1 );
let counter = 1;
let word = sorted[0]
const counted = {}
for (i = 1; i < sorted.length; ++i){
if (sorted[i] === word) counter ++
else {
counted[word]= counter;
counter = 1;
word = sorted[i]
}
}
const most = Object.entries(counted)
.sort((a,b) => a[1] > b[1] ? -1: 1)
.slice(0, 10)
.map(e => e[0])
return most;
}
console.info(fn2(list))
Вы можете сделать это так...
const list =
[ "this", "is", "a", "test", "which", "word", "wins", "top"
, "i", "don't", "know", "off", "hand", "do", "you", "this"
, "a", "a", "this", "test", "a", "a", "do", "hand"
, "hand", "a", "whatever", "what", "do", "do"
];
const getTopTen = arr =>
[...new Set(arr)]
.map(txt=>({txt, n:arr.filter(t=>t===txt).length}))
.sort((a,b)=>b.n-a.n)
.slice(0,10)
.map(({txt,n})=>txt);
console.info( getTopTen(list) );
.as-console-wrapper { max-height: 100% !important; top: 0; }
второе решение без сортировки:
const list =
[ "this", "is", "a", "test", "which", "word", "wins", "top"
, "i", "don't", "know", "off", "hand", "do", "you", "this"
, "a", "a", "this", "test", "a", "a", "do", "hand"
, "hand", "a", "whatever", "what", "do", "do"
];
function getTopTen(arr)
{
let res = []
, max = 10
, cnt = [...new Set(arr)]
.reduce((occ,txt) => { // making of { occurences , [ ...terms ] }
let n = arr.filter(t=>t===txt).length // count of sames terms
, p = occ.find(x=>x.n===n)
;
if (!p) { // new occurence
p = { n, t:[] }
let i = occ.findIndex(x=>x.n<n) // check is place
if (i<0) occ.push(p) // on bottom, or
else occ.splice(i,0,p) // just in right place
}
p.t.push(txt) // add the term in his occ list
return occ
},[])
;
for (let c of cnt) { // keep only the 10 first elments
for (let t of c.t)
{ res.push(t); if (!--max) break } // break loop on
if (!max) break // quota zero
}
return res
}
console.info( getTopTen(list) );
.as-console-wrapper { max-height: 100% !important; top: 0; }
Об этом уже говорили ([Даниил Лобан])(stackoverflow.com/a/65535865) за одно), хотя и не все (пока).
@greybeard не совсем: мое решение в настоящее время является единственным, которое использует array.filter (). Кстати, я добавил второе решение, которое не использует сортировку
Поскольку наш диапазон (частота слов) ограничен длиной списка, у нас может быть алгоритм O(n)
без логарифмического фактора, использующий сортировку подсчетом. Более того, если частоты значительно меньше n
, наши итерации будут намного короче.
Код JavaScript:
function getTopK(freq, min, max, k){
let i = min;
let j = 0;
let counts = [];
let result = new Array(k);
for (; i<=max; i++)
counts[i] = [];
for (i=0; i<freq.length; i++)
counts[freq[i][1]].push(i);
for (i=max; i>=min, j<k; i--){
for (let m=0; m<counts[i].length; m++){
result[j] = freq[counts[i][m]][0];
j++;
if (j == k)
break;
}
}
return result;
};
function f(list, k){
let max = 0;
const freq = list.reduce(function(acc, s){
acc[s] = -~acc[s];
max = Math.max(max, acc[s]);
return acc;
}, new Map())
return getTopK(Object.entries(freq), 1, max, k);
}
var list = [
"this",
"is",
"a",
"test",
"which",
"word",
"wins",
"top",
"i",
"don't",
"know",
"off",
"hand",
"do",
"you",
"this",
"a",
"a",
"this",
"test",
"a",
"a",
"do",
"hand",
"hand",
"a",
"whatever",
"what",
"do",
"do"
];
console.info(JSON.stringify(f(list, 10)));
@greybeard хорошее замечание. Определение min там неверное. Но соответствующая итерация в любом случае завершается раньше, когда достигается k.
Если я правильно понял, временная сложность здесь должна быть O(n+k), где n
— длина массива, а k
— количество элементов, которые вы хотите вернуть.
const data = ["this", "is", "a", "test", "which", "word", "wins", "top", "i", "don't", "know", "off", "hand", "do", "you", "this", "a", "a", "this", "test", "a", "a", "do", "hand", "hand", "a", "whatever", "what", "do", "do"];
function getTopOccurrences(n, list) {
const [_, arr] = list.reduce(([obj, arr], current) => {
const oldOccurrences = obj[current] || 0;
const newOccurrences = oldOccurrences + 1;
if (!arr[oldOccurrences]) { arr[oldOccurrences] = new Set(); }
if (!arr[newOccurrences]) { arr[newOccurrences] = new Set(); }
if (current in obj) {
arr[oldOccurrences].delete(current);
}
arr[newOccurrences].add(current);
obj[current] = newOccurrences;
return [obj, arr];
}, [{},[]]);
const result = [];
outer: for(let i = arr.length - 1, s = arr[i]; i >= 0; i--, s= arr[i]) {
for (let word of s){
result.push(word);
n--;
if (n <= 0) {
break outer;
}
}
}
return result;
}
console.info(getTopOccurrences(10, data));
Я видел эту проблему где-то на платформах с вызовами кодирования.