我有一个看起来像这样的对象数组:
[
{
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可以帮助解决问题,
答案 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))