简体   繁体   中英

javascript array mix by two keys

I have the following array of 3 (or more) different types and groups: Lets say colors and shapes, I want to spread that item as much as possible (not random)

['blue', 'green', 'red']
['circle', 'rect', 'tri']

they are organized in an array

[
  {type: 'blue', group: 'circle'}, {type: 'blue', group: 'rect'}, {type: 'blue',group: 'tri'},
  {type: 'green', group: 'circle'}, {type: 'green', group: 'rect'},
  {type: 'red', group: 'circle'}, {type: 'red', group: 'rect'}, {type: 'red',group: 'tri'},
]

I'm trying to sort it in a way that two different groups or types won't follow each other and also the group will follow (circle,rect,tri):

[
  {type: 'blue', group: 'circle'}, {type: 'green', group: 'rect'}, {type: 'red',group: 'tri'},
  {type: 'green', group: 'circle'}, {type: 'red', group: 'rect'}, {type: 'blue',group: 'tri'},
  {type: 'red', group: 'circle'}, {type: 'blue', group: 'rect'},
]

I was tying to go with several different ways, mapping the groups then types, mapping types then groups.

The idea is to be able to display it on screen (react) as there won't be two type / groups one next to the other.

Use forEach loop on array which need to be ordered ( shapes ) and calculate the index of colors .

 const shapes = ["circle", "rect", "tri"]; const colors = ["blue", "green", "red"]; const res = []; colors.forEach((_, ci) => { shapes.forEach((group, si) => { const type = colors[(ci + si) % colors.length]; res.push({ type, group }); }); }); console.log(res);

I have a working code, result is predictable and not random:

let types = ['blue', 'green', 'red', 'black'];
let groups = ['circle', 'rect', 'tri'];

let result = [], index1 = 0; index2 = 0;
let totalResult = types.length * groups.length;
for (let i = 0; i < totalResult; i++) {
    result.push({type: types[index1], group: groups[index2]});
    index1++;
    index2++;

    // Reset counter
    if (index1 === types.length) index1 = 0;
    if (index2 === groups.length) index2 = 0;
}

console.log(result)

And the output meet your requirement. Could you give it a try?

You could take a brute force method by generating all possible pairs and then collect the pairs by avoiding duplicates with a backtracking algorithm.

 function getAllPairs(left, right) { var pairs = []; for (let i = 0; i < left.length; i++) { for (let j = 0; j < right.length; j++) { pairs.push([left[i], right[j]]); } } return pairs; } function check(array) { const sets = [new Set, new Set]; return array.every(a => a.every((v, i) => !sets[i].has(v) && sets[i].add(v))); } function fill(result, pairs) { if (!pairs.length) return result; var left = result.slice(Math.floor(result.length / half) * half); for (let i = 0; i < pairs.length; i++) { if (check([...left, pairs[i]])) { var newResult = fill([...result, pairs[i]], [...pairs.slice(0, i), ...pairs.slice(i + 1)]); if (newResult) return newResult; } } } var type = ['blue', 'green', 'red'], group = ['circle', 'rect', 'tri'], half = Math.sqrt(type.length * group.length), result = fill([], getAllPairs(type, group)) .map(([type, group]) => ({ type, group })); console.log(result);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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