Объединение определенных объектов в массив, если несколько объектов имеют одинаковое значение для определенного ключа

#javascript #arrays #typescript #merge

#javascript #массивы #typescript #слияние

Вопрос:

Я пытаюсь вычислить наиболее используемый язык от конкретного пользователя GitHub. В каждом репозитории есть список используемых языков и целое число, которое, как я предполагаю, представляет собой количество символов на каждый язык в репозитории.

Я систематически извлекал все репозитории, принадлежащие пользователю, а затем извлекал используемые языки.

Это не совсем то, как API GitHub возвращает вещи, я просто упрощаю это, чтобы сделать мою проблему более очевидной.

Предположим, что этот массив представляет все языки, используемые во всех репозиториях пользователя.

 {
    "language": "JavaScript",
    "usage": 102378
},
{
    "language": "PHP",
    "usage": 6031
},
{
    "language": "JavaScript",
    "usage": 5479
}
 

Я хочу выполнить итерацию по этому массиву, чтобы вернуть новый со следующими значениями, которые будут представлять общее использование языка в каждом репозитории:

 {
    "language": "JavaScript",
    "usage": 107857
},
{
    "language": "PHP",
    "usage": 6031
}
 

Поскольку JavaScript это был дубликат, второе значение использования 5479 добавляется к первому, а второй объект удаляется из массива.

Звучит просто, но мне очень сложно справиться с этим.

Что я пробовал:

 let languageList = [
    {
        language: 'JavaScript',
        usage: 102379
    },
    {
        language: 'PHP',
        usage: 6031
    }
]


let language = {
    language: 'JavaScript',
    usage: 5479
}

// If array is empty, add the language object.
if(languageList.length === 0) {
    languageList.push(language)
} else {
    // boolean keeps track of existence of language in languageList
    let exists = false
    // For every language in language list...
    for(let x = 0; x < languageList; x  ) {
        // Compare the language string and if they match...
        if(languageList[x].language === language.language) {
            // Add the usage number to the existing object in languageList
            languageList[x].usage  = language.usage
            exists = true
        }
    }
    // If, after going through all array objects, it wasn't found, add language to list.
    if(!exists) {
        languageList.push(language)
    }
}
 

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

Моя проблема в том, что эта реализация никогда не обнаруживает, что язык уже существует в массиве. Я пытался заставить это работать в течение нескольких часов, и я был бы очень признателен, если бы кто-нибудь сказал мне, чего мне не хватает. Я чувствую, что это не должно быть так сложно. Спасибо!

Ответ №1:

Существует множество разных способов сделать это. Вот один:

 let list = [{
    "language": "JavaScript",
    "usage": 102378
},
{
    "language": "PHP",
    "usage": 6031
},
{
    "language": "JavaScript",
    "usage": 5479
}]

// convert the list to just an array of the language types
let result = list.map(({ language }) => language)
    // remove any duplicates
    .filter((language, index, array) => array.indexOf(language) === index)
    .map(language => ({
        language,
        // sum up the values where the language matches
        usage: list.filter(entry => entry.language === language)
            .reduce((accum, { usage }) => accum   usage, 0)
    }));
    
console.log(result);
 

Комментарии:

1. Очень признателен. Я погружаюсь в декларативное программирование и JavaScript, и у меня лучший опыт работы с Java, поэтому было сложно добиться успеха. Я упоминаю об этом, потому что очевидно, что мне нужно научиться использовать эти функции массива.

2. Конечно! У меня было то же самое при их изучении. Практика совершенствует.

Ответ №2:

Что я чувствую, это довольно просто. Допустим, у вас есть следующий массив объектов:

 [
    {
        "language": "JavaScript",
        "usage": 102378
    },
    {
        "language": "PHP",
        "usage": 6031
    },
    {
        "language": "JavaScript",
        "usage": 5479
    }
]
 

Теперь, если вы знаете, по крайней мере, ES6, вы, вероятно, сталкиваетесь с reduce() так

     let res = langaues.reduce((agg, curr) => {
        return {
            ...agg,
            [curr.language]: agg[curr.language] ? agg[curr.language]   curr.usage : curr.usage
        }
    } , {})
 

или просто с помощью цикла for…of

     let res = {};

    for(let curr of languages) {
        res = {
            ...res // previous store key/value pairs,
            [curr.language]: res[curr.language] ? res[curr.language]   curr.usage : curr.usage 
        }
    }