Односортное решение
Подход, который на самом деле избегает второго рода, безусловно, возможен. Вот одна версия, которая делает это:
const topTwoHighestPaidPlayersPerTeam = pipe (
sort (descend (prop ('pay'))),
reduce (
({result, counts}, player, {team} = player) => ({
result: counts [team] >= 2 ? result : [...result, player],
counts: {...counts, [team]: (counts[team] || 0) + 1}
}),
{result: [], counts: {}}
),
prop ('result')
)
const footballers = [{"name":"Mesut Ozil","team":"Arsenal","pay":1400000},{"name":"Lionel Messi","team":"Barcelona","pay":7300000},{"name":"Kylian Mbappe","team":"PSG","pay":1500000},{"name":"Alexis Sanchez","team":"Manchester United","pay":1990000},{"name":"Philippe Coutinho","team":"Barcelona","pay":2000000},{"name":"Neymar","team":"PSG","pay":2700000},{"name":"Luis Suarez","team":"Barcelona","pay":2500000},{"name":"Antoine Griezmann","team":"Atletico Madrid","pay":2900000},{"name":"Gareth Bale","team":"Real Madrid","pay":2200000},{"name":"Cristiano Ronaldo","team":"Juventus","pay":4100000}]
const result = topTwoHighestPaidPlayersPerTeam(footballers)
console .log (result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script> const {pipe, sort, descend, prop, reduce} = R </script>
Мы начинаем со стандартной сортировки по заработной плате, а затем перебираем их, отслеживая количество команд в группе вместе с результатами, добавляя команду всякий раз, когда подсчитываем меньше нашего максимума в 2. Мы отслеживаем это, накапливая объект с результатами и подсчетами. В конце мы просто извлекаем свойство results
. Хотя это можно сделать с помощью filter
вместо reduce
, функция, переданная в filter
, должна будет поддерживать состояние counts
, что кажется плохим соответствием для filter
.
Немного более очевидная версия
result: counts [team] < 2 ? [...result, player] : result,
не будет работать, потому что изначально количество команд не определено, а undefined < 2
дает false
. Вместо этого мы могли бы выбрать эту версию, если она кажется более понятной:
result: (counts [team] || 0) < 2 ? [...result, player] : result,
Почему нам, вероятно, не следует использовать это решение
Этот код избегает второй сортировки. Но это достигается за счет читабельности и, возможно, для коллекций разумного размера и реальной производительности.
Решение с двумя сортировками по-прежнему O (n log (n))
; выполнение чего-либо дважды не меняет показатель общей производительности c. Так что эта версия не асимптотически быстрее двухсортиментной. Но код не так читаем как Скотт Кристофер или Ори Дрори. Если мы не измерили и не можем указать на c узких мест, добавление сложности в наш код по соображениям производительности кажется полной тратой.
Поэтому я бы порекомендовал решение от Ori Drori по этому поводу. И у Скотта Кристофера также есть интересный подход.
Но этот вид техники все еще часто полезен для поддержания некоторого дополнительного состояния при сворачивании списка значений.