简体   繁体   English

JavaScript使用lodash将对象数组转换为另一个对象

[英]JavaScript transform array of objects into another using lodash

I have an array of objects that looks like this: 我有一个对象数组,如下所示:

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

Using lodash how to transform it into something that looks like this: 使用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"
      }
    ]
  },
]

The logic is as follow: 逻辑如下:

  • Every question has a combination of 2 choices where every choice is of different type example (car and food). 每个问题都有2种选择的组合,其中每种选择都是不同类型的例子(汽车和食品)。
  • Combination of different types should occur only twice (car, food). 不同类型的组合应该只发生两次(汽车,食物)。
  • No duplication of choices. 没有重复的选择。
  • The selection of choices should be randomized. 选择的选择应该是随机的。

I tried to Flatten the array using this function 我尝试使用此函数展平数组

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

but it's not what I need, and it's not random. 但这不是我需要的,而且不是随机的。 I not sure my approach is the correct one, I'm thinking I should use a filter or reduce 我不确定我的方法是否正确,我想我应该使用过滤器或减少

Any help on how to solve this would be appreciated using JS or lodash would be good. 任何有关如何解决这个的帮助将不胜感激使用JS或lodash将是好的。

You could get a combination from types and a random choices selecten with a check if a value is aleady used. 您可以从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; } 

Using Lodash 使用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> 

This was my thinking, each different combination of types needs to appear twice. 这是我的想法,每种不同类型的组合需要出现两次。 So I looped forwards over the array and combined each type with the proceeding types. 所以我在数组上循环前进,并将每种类型与前进类型组合在一起。 Then I looped backwards over the array and combined each type with the preceeding types. 然后我在数组上向后循环,并将每种类型与前面的类型组合在一起。 At the same time I used Math.random() to pick a random choice from the choices subarray. 与此同时,我使用Math.random()choices子阵列中选择一个随机选择。 The only problem is that this does not enforce strict duplicate elimination but relies on RNG to guarantee a low chance of duplicates. 唯一的问题是,这不会强制执行严格的重复删除,但依赖于RNG来保证重复的可能性较低。 You should be able to add duplicate checking code inside each loop just before you create the new question. 在创建新问题之前,您应该能够在每个循环中添加重复的检查代码。

 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)) 

You can use a recursive function to keep removing items from each array until you're left without enough options remaining to fill in any more questions. 您可以使用递归函数继续从每个数组中删除项目,直到您没有剩余足够的选项来填写任何其他问题。

To help do this, we have functions which take in an array, and return a random item, plus the array without that item. 为了做到这一点,我们有一些函数接收一个数组,并返回一个随机项,加上没有该项的数组。 We can then build the questions with that data, ensuring that each item is only used once. 然后,我们可以使用该数据构建问题,确保每个项目仅使用一次。

 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)) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM