[英]JavaScript transform array of objects into another using 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 }
],
})
));
但這不是我需要的,而且不是隨機的。 我不確定我的方法是否正確,我想我應該使用過濾器或減少
任何有關如何解決這個的幫助將不勝感激使用JS或lodash將是好的。
您可以從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; }
使用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>
這是我的想法,每種不同類型的組合需要出現兩次。 所以我在數組上循環前進,並將每種類型與前進類型組合在一起。 然后我在數組上向后循環,並將每種類型與前面的類型組合在一起。 與此同時,我使用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))
您可以使用遞歸函數繼續從每個數組中刪除項目,直到您沒有剩余足夠的選項來填寫任何其他問題。
為了做到這一點,我們有一些函數接收一個數組,並返回一個隨機項,加上沒有該項的數組。 然后,我們可以使用該數據構建問題,確保每個項目僅使用一次。
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.