@shobanof

Как извлечь случайный элемент из вложенных массивов?

const state = {
  themes: {
    css: [
      {id: 1, description: "css string 1"},
      {id: 2, description: "css string 2"},
      {id: 3, description: "css string 3"},
      {id: 4, description: "css string 4"}
    ],
    js: [
      {id: 1, description: "js string 1"},
      {id: 2, description: "js string 2"},
      {id: 3, description: "js string 3"},
      {id: 4, description: "js string 4"}
    ],
    react: [
      {id: 1, description: "React string 1"},
      {id: 2, description: "React string 2"},
      {id: 3, description: "React string 3"},
      {id: 4, description: "React string 4"}
    ]
  }
}

const showCard = () => {
  // const deckOfReact = state.themes.react
  // const itemReact = deckOfReact[Math.floor(Math.random() * deckOfReact.length)]
  // alert(itemReact.description)
  
  const commonDeck = state.themes
  const item = 
  alert(item.description)
}
  • Вопрос задан
  • 98 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
Извлечение случайного элемента массива выносим в отдельную функцию:

const random = arr => arr[Math.random() * arr.length | 0];

Дальше можно получить случайный элемент случайного элемента:

const item = random(random(Object.values(state.themes)));

Или вложенный массив превратить в плоский и получить случайный элемент один раз:

const item = random(Object.values(state.themes).flat());

Какой из вариантов предпочесть? Зависит от того, как должны распределяться вероятности выпадения элементов - в случае, если выбирать элемент в два приёма, и размеры вложенных массивов различны, вероятности будут разными для разных массивов. Предположим, есть два вложенных массива, в одном два элемента, во втором сто. Получается, у элементов первого массива шанс быть выбранными один к четырём (один из двух массивов, один из двух элементов - 0.5 умножается на 0.5), а у элементов второго - один к двумстам (0.5 * 0.01).

То есть, если должны быть равны вероятности выпадения элементов - объединяем вложенные массивы в один. Если равными должны быть вероятности принадлежности выбранного элемента к вложенным массивам, то выбираем сначала массив, а потом элемент внутри него.

Но что если вероятности выпадения элементов должны быть равны, а размеры вложенных массивов велики, и не хотелось бы тратить на их объединение ни время, ни память? Возвращаемся к двум выборам, но выбирать вложенные массивы надо не с равными вероятностями, а учитывая их размеры:

function weightedRandom(arr, key) {
  const rand = Math.random() * arr.reduce((acc, n) => acc + n[key], 0);
  let sum = 0;
  return arr.find(n => (sum += n[key]) > rand);
}

const item = random(weightedRandom(Object.values(state.themes), 'length'));
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы