Как вернуть сумму значений из массива объектов на основе массива объектов - PullRequest
0 голосов
/ 18 июня 2019

У меня есть следующий пример массива объектов, каждый объект в массиве содержит id, personId, scores и, наконец, score. В некоторых объектах scores является либо null, либо содержит другой массив объектов, которые являются баллами. В других объектах score может содержать значение вместо null. Наконец, может быть случай, когда объект может содержать как scores, так и score.

const startingArray = [
  {
    id: 1,
    personId: 1,
    scores: [
      {
        id: 1,
        title: 'Google',
        score: 12
      },
      {
        id: 2,
        title: 'Bing',
        score: 23
      },
      {
        id: 3,
        title: 'Facebook',
        score: 34
      }
    ],
    score: null
  },
  {
    id: 2,
    personId: 1,
    scores: null,
    score: 123
  },
  {
    id: 3,
    personId: 2,
    scores: [
      {
        id: 4,
        title: 'Google',
        score: 7
      },
      {
        id: 5,
        title: 'Bing',
        score: 32
      },
      {
        id: 6,
        title: 'Facebook',
        score: 9
      }
    ],
    score: null
  },
  {
    id: 4,
    personId: 3,
    scores: null,
    score: 106
  },
  {
    id: 5,
    personId: 3,
    scores: [
      {
        id: 7,
        title: 'Google',
        score: 6
      },
      {
        id: 8,
        title: 'Bing',
        score: 4
      },
      {
        id: 9,
        title: 'Facebook',
        score: 3
      }
    ],
    score: 5
  }
]

Я могу отфильтровать startingArray, чтобы вернуть действительные объекты для человека:

startingArray.filter(item => item.personId === personId)

И я также выяснил, как использовать map и reduce, чтобы вернуть значение score предметов для человека:

startingArray.filter(item => item.personId === personId).map(item => item.score).reduce((a, b) => a + b, 0)

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

В конечном итоге я должен позвонить personScores(1) и получить общее количество баллов за человека 1 (т.е. 69), или позвонить personScores(3) и получить 124 (то есть 106 + 13 +). 5).

Ответы [ 4 ]

4 голосов
/ 18 июня 2019

Не ясно, может ли человек появляться более чем один раз в startingArray. Предполагая, что они могут появиться более одного раза:

Один из популярных способов сделать это - использовать Array#reduce, но я бы просто использовал пару for-of циклов. Вам не нужно предварительно filter (хотя некоторые предпочитают, что хорошо).

Вот версия for-of:

function personScore(personId) {
  let sum = 0;
  for (const entry of startingArray) {
    if (entry.personId === personId) {
      sum += entry.score || 0;
      if (entry.scores) {
        for (const {score} of entry.scores) {
          sum += score;
        }
      }
    }
  }
  return sum;
}

Live Copy:

const startingArray = [
  {
    id: 1,
    personId: 1,
    scores: [
      {
        id: 1,
        title: 'Google',
        score: 12
      },
      {
        id: 2,
        title: 'Bing',
        score: 23
      },
      {
        id: 3,
        title: 'Facebook',
        score: 34
      }
    ],
    score: null
  },
  {
    id: 2,
    personId: 1,
    scores: null,
    score: 123
  },
  {
    id: 3,
    personId: 2,
    scores: [
      {
        id: 4,
        title: 'Google',
        score: 7
      },
      {
        id: 5,
        title: 'Bing',
        score: 32
      },
      {
        id: 6,
        title: 'Facebook',
        score: 9
      }
    ],
    score: null
  },
  {
    id: 4,
    personId: 3,
    scores: null,
    score: 106
  },
  {
    id: 5,
    personId: 3,
    scores: [
      {
        id: 7,
        title: 'Google',
        score: 6
      },
      {
        id: 8,
        title: 'Bing',
        score: 4
      },
      {
        id: 9,
        title: 'Facebook',
        score: 3
      }
    ],
    score: 5
  }
]
function personScore(personId) {
  let sum = 0;
  for (const entry of startingArray) {
    if (entry.personId === personId) {
      sum += entry.score || 0;
      if (entry.scores) {
        for (const {score} of entry.scores) {
          sum += score;
        }
      }
    }
  }
  return sum;
}
console.log(personScore(1));

Вот reduce версия:

function personScore(personId) {
  return startingArray.reduce((sum, entry) => {
    if (entry.personId !== personId) {
      return sum;
    }
    sum += entry.score || 0;
    if (entry.scores) {
      sum += entry.scores.reduce((acc, {score}) => acc + score, 0);
    }
    return sum;
  }, 0);
}

Live Copy:

const startingArray = [
  {
    id: 1,
    personId: 1,
    scores: [
      {
        id: 1,
        title: 'Google',
        score: 12
      },
      {
        id: 2,
        title: 'Bing',
        score: 23
      },
      {
        id: 3,
        title: 'Facebook',
        score: 34
      }
    ],
    score: null
  },
  {
    id: 2,
    personId: 1,
    scores: null,
    score: 123
  },
  {
    id: 3,
    personId: 2,
    scores: [
      {
        id: 4,
        title: 'Google',
        score: 7
      },
      {
        id: 5,
        title: 'Bing',
        score: 32
      },
      {
        id: 6,
        title: 'Facebook',
        score: 9
      }
    ],
    score: null
  },
  {
    id: 4,
    personId: 3,
    scores: null,
    score: 106
  },
  {
    id: 5,
    personId: 3,
    scores: [
      {
        id: 7,
        title: 'Google',
        score: 6
      },
      {
        id: 8,
        title: 'Bing',
        score: 4
      },
      {
        id: 9,
        title: 'Facebook',
        score: 3
      }
    ],
    score: 5
  }
]
function personScore(personId) {
  return startingArray.reduce((sum, entry) => {
    if (entry.personId !== personId) {
      return sum;
    }
    sum += entry.score || 0;
    if (entry.scores) {
      sum += entry.scores.reduce((acc, {score}) => acc + score, 0);
    }
    return sum;
  }, 0);
}
console.log(personScore(1));

Если они могут появиться только один раз, массив на самом деле не способ организовать эти данные (я бы использовал объект или Map), но с массивом я бы использовал find, чтобы найти их , а затем просто получить информацию из этой записи:

function personScore(personId) {
  const entry = startingArray.find(entry => entry.personId === personId);
  if (!entry) {
    return 0;
  }
  let sum = entry.score || 0;
  if (entry.scores) {
    for (const {score} of scores) {
      sum += score;
    }
  }
  return sum;
}

Live Copy:

const startingArray = [
  {
    id: 1,
    personId: 1,
    scores: [
      {
        id: 1,
        title: 'Google',
        score: 12
      },
      {
        id: 2,
        title: 'Bing',
        score: 23
      },
      {
        id: 3,
        title: 'Facebook',
        score: 34
      }
    ],
    score: null
  },
  {
    id: 2,
    personId: 1,
    scores: null,
    score: 123
  },
  {
    id: 3,
    personId: 2,
    scores: [
      {
        id: 4,
        title: 'Google',
        score: 7
      },
      {
        id: 5,
        title: 'Bing',
        score: 32
      },
      {
        id: 6,
        title: 'Facebook',
        score: 9
      }
    ],
    score: null
  },
  {
    id: 4,
    personId: 3,
    scores: null,
    score: 106
  },
  {
    id: 5,
    personId: 3,
    scores: [
      {
        id: 7,
        title: 'Google',
        score: 6
      },
      {
        id: 8,
        title: 'Bing',
        score: 4
      },
      {
        id: 9,
        title: 'Facebook',
        score: 3
      }
    ],
    score: 5
  }
]
function personScore(personId) {
  const entry = startingArray.find(entry => entry.personId === personId);
  if (!entry) {
    return 0;
  }
  let sum = entry.score || 0;
  if (entry.scores) {
    for (const {score} of scores) {
      sum += score;
    }
  }
  return sum;
}
console.log(personScore(1));
1 голос
/ 18 июня 2019

Вы можете использовать уменьшение, чтобы получить сумму и либо использовать уменьшение снова, если у нас есть массив для оценки, или просто добавить то, что на счет

function getPersonScore(arr, id) {
  const filtered = id ? arr.filter(e => e.personId === id) : arr;
  return filtered.reduce((a, b) => {
    if (Array.isArray(b.scores)) a += getPersonScore(b.scores);
    return a + (b.score || 0);
  }, 0);
}


console.log(getPersonScore(startingArray, 1));
<script>
const startingArray = [
  {
    id: 1,
    personId: 1,
    scores: [
      {
        id: 1,
        title: 'Google',
        score: 12
      },
      {
        id: 2,
        title: 'Bing',
        score: 23
      },
      {
        id: 3,
        title: 'Facebook',
        score: 34
      }
    ],
    score: null
  },
  {
    id: 2,
    personId: 1,
    scores: null,
    score: 123
  },
  {
    id: 3,
    personId: 2,
    scores: [
      {
        id: 4,
        title: 'Google',
        score: 7
      },
      {
        id: 5,
        title: 'Bing',
        score: 32
      },
      {
        id: 6,
        title: 'Facebook',
        score: 9
      }
    ],
    score: null
  },
  {
    id: 4,
    personId: 3,
    scores: null,
    score: 106
  },
  {
    id: 5,
    personId: 3,
    scores: [
      {
        id: 7,
        title: 'Google',
        score: 6
      },
      {
        id: 8,
        title: 'Bing',
        score: 4
      },
      {
        id: 9,
        title: 'Facebook',
        score: 3
      }
    ],
    score: 5
  }
];
</script>
0 голосов
/ 18 июня 2019

Сначала find нужного вам человека, затем с помощью reduce добавьте его scores и, наконец, добавьте его к score.

const startingArray = [{id:1,personId:1,scores:[{id:1,title:'Google',score:12},{id:2,title:'Bing',score:23},{id:3,title:'Facebook',score:34}],score:null},{id:2,personId:1,scores:null,score:123},{id:3,personId:2,scores:[{id:4,title:'Google',score:7},{id:5,title:'Bing',score:32},{id:6,title:'Facebook',score:9}],score:null},{id:4,personId:3,scores:null,score:106},{id:5,personId:3,scores:[{id:7,title:'Google',score:6},{id:8,title:'Bing',score:4},{id:9,title:'Facebook',score:3}],score:5}];

const personScores = id => {
  let { scores, score } = startingArray.find(({ personId }) => personId);
  let finalScore = 0;
  if (score && score.length) finalScore += (Array.isArray(score) ? score.reduce((a, { score }) => a + score, 0) : score);
  if (scores && scores.length) finalScore += (Array.isArray(scores) ? scores.reduce((a, { score }) => a + score, 0) : scores);
  return finalScore;
};

console.log(personScores(1));
console.log(personScores(3));

(Приведенный выше код проверяет как score и scores, чтобы определить, являются ли они массивами, так и выполняет соответствующую логику соответственно)

0 голосов
/ 18 июня 2019
const personScores = (id, arr) => {
  // error catching
  if (!Array.isArray(arr)) {
    throw new Error('Input array is not an array');
  }
  if (id >= arr.length) {
    throw new Error(`Id ${id} out of array range (length ${arr.length})`);
  }
  if (!('scores' in arr[id])) {
    throw new Error(`scores key missing in input array`);
  }
  if (!Array.isArray(arr[id].scores)) {
    throw new Error(`Scores of input id ${id} not an array`);
  }

  // iterate scores array of startingArray[id], defaultValue of sum is 0
  return arr[id].scores.reduce((sum, scoreObj) => {
    if ('score' in scoreObj && !isNaN(parseInt(scoreObj.score, 10))) {
      sum += parseInt(scoreObj.score, 10);
    }
    return sum;
  }, 0); // defaultValue of the reducer
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...