Привет, друзья помогите разобраться с интересной задачей на js
Написать функцию которая будет возвращать имя счастливчика, того кто чаще всего встречается в массиве
['Женя','Женя', 'Иван', 'Женя', 'Виктор', 'Виктор','Константин', 'Виктор', 'Виктор']
Функция должна возвращать
{lucky: "Виктор", loser:"Константин", other:["Женя","Иван"]}
Моя решение на котором засстрял во вложении введите сюда код
function nameFind(array) {
let first = []
let second = []
let third = []
let forth = []
for (let i = 0; i < array.length; i++) {
if (array[i] === 'Женя') {
first.push(array[i])
}
if (array[i] === 'Иван') {
second.push(array[i])
}
if (array[i] === 'Виктор') {
third.push(array[i])
}
if (array[i] === 'Константин') {
forth.push(array[i])
}
}
console.log(Object.assign({}, [first, second, third, forth]))
}
let names = ['Женя', 'Женя', 'Иван', 'Женя', 'Виктор', 'Виктор', 'Константин', 'Виктор', 'Виктор']
console.log(nameFind(names))
Ответы (4 шт):
Если всегда только один победитель и один проигравший то вот:
const arr = ['Женя', 'Иван', 'Женя', 'Виктор', 'Виктор', 'Константин', 'Виктор', 'Виктор']
function getWinner(input) {
let output = []
let loserIndex = 0
let winnerIndex = 0
for (let i of input) {
if(!output.flat().includes(i)) {
output.push([i])
} else {
for (let j in output) {
if(output[j][0] === i) {
output[j].push(i)
break
}
}
}
}
for (let i in output) {
if(output[i] > output[i-1]) {
loserIndex = i
}
else if(output[i] < output[i-1]) {
winnerIndex = i
}
}
return {
lucky: output[winnerIndex][0],
loser: output[loserIndex][0],
other: output.filter(e => e[0] !== output[winnerIndex][0] && e[0] !== output[loserIndex][0]).map(e => e[0]),
}
}
console.log(getWinner(arr))
Не считаю свой ответ оптимизированным т.к. по 100 раз идёт проход по массивам, но всё же лучше чем ничего.
Объяснение
Сначала создаём переменые для будущего: входные данные, индекс лузера, индекс победителя, другие имена. Далее проходимся по входным данным, если у нас нет такого то имени, тогда создаём новый массив в выходных данных. В противоположном случае проходимся по выходным данным и проверяем является ли именя тем которые мы ищем, и если является добавляем его в массив, а дальше прекращаем цикл, т.к. мы уже нашли нужное имя. Далее проходимся по выходным данным и проверяем какие индексы у подителя и проигравшего. Далее возвращаем имена победителя и проигравшего и в самом конце просто проходимся по выходному массиву и убираем там массивы с именами победителя и проигравшего, и снова проходимся по этому родительскому массиву, только заменяя все значения на первое попавшееся имя из массива ребёнка.
Скажу сразу, что с ожидаемым выходом я не согласен т.к.:
Не понятно почему лузером стал именно
Константин, хотяИвантоже встречается 1 разНе понятно что будет, если будут несколько лузеров и счастливчиков
В моём алгоритме логика выхода такова:
В массив счастливчиков входят все, у кого частота самая высокая т.е. если 2 имени встречаются по 5 раз и это наибольшая частота, то оба станут счастливчиками
В массив лузеров входят все, у кого частота самая низкая т.е. если 2 имени встречаются по 1-му разу и это наименьшая частота, то оба станут лузерами
Все остальне попадают в массив остальных
Логика самого алгоритма:
Сначала проходимся по массиву и собираем данные в словарик
namesCountMapо том, сколько раз каждое имя встречаетсяПроходимся по предыдущему словарику и группируем имена по кол-ву совпадений в словарике
countNamesMapПреобразуем данные второго словарика в массив, сортируем и преобразуем элементы
В первом элементе этого массива у нас список счасливчиков, забираем его с помощью pop
В последнем элементе этого массива у нас список лузеров, забираем его с помощью shift
Все оставшиеся элементы - это остальные
Если в списке было 1 имя, то возвращаем не массив, а имя
Если список был пуст или было больше 1-ого имени, то возращаем массив
const names = ['Женя', 'Женя', 'Иван', 'Женя', 'Виктор', 'Виктор', 'Константин', 'Виктор', 'Виктор'];
const getStringOrArr = (arr) => arr.length === 1 ? arr[0] : arr;
const nameFind = (array) => {
const namesCountMap = new Map();
const countNamesMap = new Map();
for (const el of array) {
namesCountMap.set(el, (namesCountMap.get(el) || 0) + 1);
}
for (const [name, count] of namesCountMap) {
if (countNamesMap.has(count)) {
countNamesMap.get(count).push(name);
} else {
countNamesMap.set(count, [name]);
}
}
const sortedArr = [...countNamesMap]
.sort((a, b) => b[0] - a[0])
.map(x => x[1]);
const winners = sortedArr.shift() || [];
const loosers = sortedArr.pop() || [];
const others = sortedArr.flat();
return {
lucky: getStringOrArr(winners),
loser: getStringOrArr(loosers),
other: getStringOrArr(others),
}
}
console.log(1, nameFind([]));
console.log(2, nameFind(['a']));
console.log(3, nameFind(['a', 'b']));
console.log(4, nameFind(['a', 'b', 'a']));
console.log(5, nameFind(['a', 'b', 'a', 'b', 'a', 'c', 'd']));
console.log(6, nameFind(['a', 'b', 'a', 'b', 'a', 'c', 'd', 'e', 'e', 'e']));
console.log(7, nameFind(['a', 'b', 'a', 'b', 'a', 'c', 'd', 'e', 'e', 'e', 'f', 'f']));
console.log('names', nameFind(names));
Ещё один вариант , покорче..
let m = ['Женя','Женя', 'Иван', 'Женя', 'Виктор', 'Виктор','Константин', 'Виктор', 'Виктор'];
function sorting (m) {
m = m.sort();
let name = m[0];
let res = []
for(let i = 0; i <= m.length; i++){
if(name != m[i]) {
name = m[i];
res.push(m[i-1])
}
}
return {lucky: res[0], loser:res[res.length-1], other:res.slice(1,-1)}
}
console.log(sorting(m))
Как правильно заметил @EzioMercer в комментариях под моим ответом
Добавьте всего 1 дополнительную строку 'A' и сразу счастилвчиком станет она.
Немного исправил предыдущий вариант..
let m = ['A', 'Женя', 'Женя', 'Иван', 'Женя', 'Виктор', 'Виктор', 'Константин', 'Виктор', 'Виктор'];
let j = 1;
function sorting(m) {
m = m.sort();
let name = m[0];
let obj = [];
for (let i = 0; i <= m.length; i++) {
if (i != 0 && name == m[i]) j++;
if (name != m[i]) {
obj.push( {name: m[i - 1], count: j} );
name = m[i];
j = 1;
}
}
let res = obj.sort(function(a, b) {
return b.count - a.count;
}).map(e => {
return e.name;
});
return { lucky: res[0], loser: res[res.length - 1], other: res.slice(1, -1) }
}
console.log(sorting(m))
Вот написал такое. Возможно можно как-то сократить.
function nameFind(array) {
const countDuplicates = array.reduce((acc, cur) => {
acc[cur] = (acc[cur] || 0) + 1;
return acc // отдаст {Женя: 3, Иван: 1, Виктор: 4, Константин: 1}
}, {})
const sortedValues = Object.entries(countDuplicates).sort(([aKey, aValue], [bKey, bValue]) => bValue - aValue).map(i => i[0]) // сортировка по количеству и возврат только имен
return {
lucky: sortedValues[0],
loser: sortedValues[sortedValues.length - 1],
others: sortedValues.slice(1, sortedValues.length - 1)
}
}
let names = ['Женя', 'Женя', 'Иван', 'Женя', 'Виктор', 'Виктор', 'Константин', 'Виктор', 'Виктор']
console.log(nameFind(names))