Вы можете упростить это до чего-то подобного, используя flat
и reduce
:
const input = [["a", "b"],["c", "d"],["b", "d"],["c", "a", "b"],["a", "b", "c", "d"]]
,output = input.flat().reduce((acc, a) =>
((acc[a] = acc[a] || {keyword: a, frequency: 0})["frequency"]++, acc)
,{})
console.log(Object.values(output))
Если flat
не не поддерживается , используйте [].concat(...input).reduce()
мне нравится устранять ошибочные случаи сначала - и возврат из функции рано так, чтобы 'счастливый путь' остался невложенным, например.
if (some error condition)
{
//handle it
return;
}
//implicit else for happy path
...
если легко определить продвижение условий к счастливому пути, то любой ценой помещенный, что пункт сначала (благодарит Marcin!)
Это - очень отдельный вид решения, но я склонен помещать свои состояния ошибки сначала под отговоркой группировки как код вместе. Таким образом, если я делаю что-то, и это перестало работать, проверка на тот отказ является действительно на самом деле частью выполнения этого что-то; если я поместил проверку на отказ и действие на основе этого в начале моего кода, я сгруппировал свое действие и сложный ответ на то действие вместе (работающий при условии, что результат отказа является на самом деле более сложным случаем возврата, чем успех).
если его 1 или 2 строки и ранний возврат, я поместил его наверху - особенно если в начале функции. это почти читает как контракт. иначе я иду с "положительными условиями перед отрицательным" правилом.
Первое кажется немного предпочтительным для меня, в котором это избегает двойного отрицания в условном выражении.
Кроме этого, Вы создали вещи так, чтобы Вы не могли действительно
// do stuff
после Вас
// deal with problem
так же кроме того каждый кажется столь же хорошим как другой.
Это зависит от того, что более ясно Вам. Я имею в виду, что имеет больше смысла, что noProblems имеет истинное значение или что это имеет ложное значение.
Например, для isDeviceEnabled () я всегда проверял бы на истинный результат, как "Включено" имеет неявно положительное значение. Для неявной отрицательной величины мы могли проверить, например, на "isMemoryAvailable ()", возможно, потому что необходимо проверить, только если больше нет комнаты для новых объектов/массивов или других данных.
Возможно, это зависит от конвенций языка или других факторов, но я чувствую, что номинальный случай должен быть наверху, и ответвления должны содержать исключительные условия. Это делает код намного легче читать. Это особенно верно, когда существует много исключительных условий, и в большинстве случаев существует. Вы сможете легко предположить, что автор ожидает, что этот определенный путь будет взят большую часть времени и поймет код, легче этот путь.
От раздела "Code complete, 2nd edition" 15.1:
Путем помещения наиболее распространенных случаев сначала, Вы минимизируете объем кода обработки случая исключения, который кто-то должен прочитать для нахождения обычных случаев. Вы повышаете эффективность, потому что Вы минимизируете количество тестов, которые код делает для нахождения наиболее распространенных случаев.
Почему бы не создать одну точку выхода из функции и сделать надлежащую очистку там вместо того, чтобы иметь несколько возвратов...
DWORD bRetVal= TRUE;
if(foo is null)
{
bRetVal = FALSE;
goto Error;
}
else
{
// do something
}
Exit:
return bRetVal;
Как с попыткой/выгодой я делаю нормальный поток и затем обрабатываю условия исключений.
Это не означает, что ошибочной проверки/вычищения не происходит сначала, но это - то, если я не доверяю тому, что было передано мне.
например,
if (foo is null) then
// bail
end if
if (bar == foo) then
// foo hasn't been changed... print the regular report
else
// foo has changed, run the reconciliation report instead.
end if
Мне нравится, когда счастливая история течет как прямая линия и несчастная история для отделения на ее собственную шпору.