JavaScript使用lodash

时间:2019-06-05 11:11:51

标签: javascript ecmascript-6 lodash

我有一个看起来像这样的对象数组:

[
  {
    type: 'car',
    choices: [
      'audi',
      'honda',
      'bmw',
      'ford'
    ],
  },
  {
    type: 'drink',
    choices: [
      'soda',
      'water',
      'tea',
      'coffee'
    ],
  },
  {
    type: 'food',
    choices: [
      'chips',
      'pizza',
      'cookie',
      'pasta'
    ],
  }
]

使用lodash如何将其转换为如下所示的内容:

[
  {
    question: [
      {
        drink: "tea"
      },
      {
        car: "bmw"
      }
    ]
  },
  {
    question: [
      {
        food: "cookie"
      },
      {
        car: "ford"
      }
    ]
  },
  {
    question: [
      {
        drink: "soda"
      },
      {
        food: "pizza"
      }
    ]
  },
  {
    question: [
      {
        food: "chips"
      },
      {
        drink: "water"
      }
    ]
  },
  {
    question: [
      {
        car: "audi"
      },
      {
        food: "pasta"
      }
    ]
  },
  {
    question: [
      {
        car: "honda"
      },
      {
        drink: "coffee"
      }
    ]
  },
]

逻辑如下:

  • 每个问题都有两个选择的组合,其中每个选择属于不同类型的示例(汽车和食物)。
  • 不同类型的组合只能出现两次(汽车,食物)。
  • 没有重复的选择。
  • 选择的选项应该是随机的。

我尝试使用此函数展平数组

    let flattenItems = _.flatMap(items, ({ type, choices}) =>
      _.map(choices, choice => ({
        question: [
          { type: type, choice: choice },
          { type: type, choice: choice }
        ],
      })
    ));

但这不是我需要的,也不是随机的。我不确定我的方法是正确的,我在想应该使用过滤器还是reduce

使用JS或lodash可以帮助解决问题,

4 个答案:

答案 0 :(得分:2)

您可以从types和随机choices中选择一个组合,并检查是否使用了有铅的值。

function getCombinations(array, size) {

    function c(left, right) {

        function getQuestion({ type, choices }) {
            var random;
            do {
                random = choices[Math.floor(Math.random() * choices.length)];
            } while (taken.get(type).has(random))
            taken.get(type).add(random);
            return { [type]: random };
        }

        left.forEach((v, i, a) => {
            var temp = [...right, v];
            if (temp.length === size) {
                result.push({ question: temp.map(getQuestion) });
            } else {
                c([...a.slice(0, i), ...a.slice(i + 1)], temp);
            }
        });
    }

    var result = [],
        taken = new Map(array.map(({ type }) => [type, new Set]));

    c(array, []);
    return result;
}

var data = [
    { type: 'car', choices: ['audi', 'honda', 'bmw', 'ford'] },
    { type: 'drink', choices: ['soda', 'water', 'tea', 'coffee'] },
    { type: 'food', choices: ['chips', 'pizza', 'cookie', 'pasta'] }
];

console.log(getCombinations(data, 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:2)

使用 Lodash

function randomizedQues(items) {
  let result = [];
  let flattenItems = _.flatMap(items, ({ type, choices }) =>
    _.map(choices, choice => ({ type: type, choice: choice })
  ))

  while(flattenItems.length > 1) {
    let r1 = _.random(flattenItems.length - 1),
        e1 = flattenItems[r1];

    let r2 = _.random(flattenItems.length - 1),
        e2 = flattenItems[r2];      

    if(e1.type === e2.type) continue

    result.push({ question: [
        {[e1.type]: e1.choice},
        {[e2.type]: e2.choice}
      ] 
    })
    _.pullAt(flattenItems, [r1, r2])
  }
  return result
}

let items = [{"type":"car","choices":["audi","honda","bmw","ford"]},{"type":"drink","choices":["soda","water","tea","coffee"]},{"type":"food","choices":["chips","pizza","cookie","pasta"]}]

console.log(randomizedQues(items))
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

答案 2 :(得分:1)

这是我的想法,每种不同的类型组合都需要出现两次。因此,我在数组上向前循环,并将每种类型与进行类型组合在一起。 然后,我向后遍历数组,并将每种类型与前面的类型组合在一起。同时,我使用Math.random()choices子数组中选择一个随机选择。唯一的问题是,这并不强制严格消除重复,而是依靠RNG来保证重复的机会很小。在创建新问题之前,您应该应该能够在每个循环中添加重复的检查代码。

function buildQuestions(data) {
  const questions = []
  for (let i = 0; i < data.length; i++)
    for (let j = i + 1; j < data.length; j++)
      questions.push({question: [{[data[i].type]: data[i].choices[Math.round(Math.random() * (data[i].choices.length - 1))]},
          {[data[j].type]: data[j].choices[Math.round(Math.random() * (data[j].choices.length - 1))]}]})

  for (let i = data.length - 1; i > 0; i--)
    for (let j = i - 1; j >= 0; j--)
      questions.push({question: [{[data[i].type]: data[i].choices[Math.round(Math.random() * (data[i].choices.length - 1))]},
          {[data[j].type]: data[j].choices[Math.round(Math.random() * (data[j].choices.length - 1))]}]})

  return questions
}

const choices = [{ type: 'car',choices: ['audi','honda','bmw','ford'],},{type: 'drink', choices: ['soda','water','tea','coffee'],},{type: 'food',choices: ['chips','pizza','cookie','pasta'],}]

console.log(buildQuestions(choices))

答案 3 :(得分:1)

您可以使用递归函数从每个数组中删除项目,直到剩下的选项不足以填补其他问题为止。

为帮助实现此目的,我们提供了一些函数,这些函数接收一个数组,并返回一个随机项目,再加上不包含该项目的数组。然后,我们可以使用该数据构建问题,确保每个项目仅使用一次。

const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x)

const data = [
    { type: 'car', choices: ['audi', 'honda', 'bmw', 'ford'] },
    { type: 'drink', choices: ['soda', 'water', 'tea', 'coffee'] },
    { type: 'food', choices: ['chips', 'pizza', 'cookie', 'pasta'] }
];

const getArrayIndexPair = array => [
  array,
  getRandom(array),
];

const subtractItemFromArray = ([array, index]) => [
  array.slice(index, index + 1)[0],
  [
    ...array.slice(0, index),
    ...array.slice(index + 1, array.length)
  ]
];

const getRandom = array => Math.floor(Math.random()*array.length);
const takeRandom = pipe(
  getArrayIndexPair,
  subtractItemFromArray,
);

const choicesKeyedByType = data
  .reduce((p, c) => ({
    ...p,
    [c.type]: c.choices,
  }), {})

const formQuestions = (choices, questions=[]) => {
  if (Object.keys(choices).length <= 1) {
    return questions;
  }

  const [keyOne, remainingKeys] = takeRandom(Object.keys(choices));
  const [keyTwo] = takeRandom(remainingKeys);
  
  const [choiceOne, remainingKeyOneChoices] = takeRandom(choices[keyOne]);
  const [choiceTwo, remainingKeyTwoChoices] = takeRandom(choices[keyTwo]);

  const newChoices = {
    ...choices,
    [keyOne]: remainingKeyOneChoices,
    [keyTwo]: remainingKeyTwoChoices,
  };
  
  const newChoicesWithoutEmpty = Object.keys(newChoices)
    .filter(key => newChoices[key].length > 0)
    .reduce((p, c) => ({
      ...p,
      [c]: newChoices[c]
    }), {});
    
  const newQuestions = [
    ...questions,
    {
      [keyOne]: choiceOne,
      [keyTwo]: choiceTwo,
    }
  ];
  
  return formQuestions(
    newChoicesWithoutEmpty,
    newQuestions,
  );
};

console.dir(formQuestions(choicesKeyedByType))