Reputation: 597
I need to shuffle some elements of an array with a specific step.
I have this array of object :
[
{
"_id": "aze54aze",
"boosted": false
},
{
"_id": "94v2d9e3",
"boosted": false
},
{
"_id": "999f5a8az4",
"boosted": false
},
{
"_id": "e9d29a9g",
"boosted": true
},
{
"_id": "f8f2a9f6a",
"boosted": false
},
{
"_id": "pe55z8a",
"boosted": false
},
{
"_id": "pvazpd97",
"boosted": false
},
{
"_id": "ft8azefze",
"boosted": true
},
]
I want the boosted objects to be shuffled within the array with a step of two objects between them. In order to not put them all at the beginning of the array, I need them to be "hidden" in the array.
That means that the first boosted object will go at the first position, then two normal objects, then the second boosted object, then the other normal objects.
Can I achieve this with Lodash built-in functions ?
Upvotes: 2
Views: 63
Reputation: 48407
You can do this by using native ES6
javascript features like filter
, reduce
methods and spread syntax
First of all, you should separate the boosted
and normal
array items. Then create a new array where first boosted object will go at the first position, then two normal objects, then second boosted object and so on...
I used splice
method in order to remove
items from normal
or boosted
array after I added them to my result array. Why this ? Because at the end I need to concat
the remaining elements to my result.
var arr = [ { "_id": "aze54aze", "boosted": false }, { "_id": "94v2d9e3", "boosted": false }, { "_id": "999f5a8az4", "boosted": false }, { "_id": "e9d29a9g", "boosted": true }, { "_id": "f8f2a9f6a", "boosted": false }, { "_id": "pe55z8a", "boosted": false }, { "_id": "pvazpd97", "boosted": false }, { "_id": "ft8azefze", "boosted": true }, ]
var boosted = arr.filter(item => item.boosted);
var boosted_copy = boosted.slice();
var normal = arr.filter(item => !item.boosted);
var result = boosted.reduce((res, item, i) => {
res.push(boosted_copy.splice(0, 1)[0], ...normal.splice(0, i * 2 + 2));
return res;
}, []).concat(boosted_copy, normal);
console.log(result);
Upvotes: 2
Reputation: 18525
With ES6 you could achieve that by using reduce and spread syntax:
const data = [ { "_id": "aze54aze", "boosted": false }, { "_id": "94v2d9e3", "boosted": false }, { "_id": "999f5a8az4", "boosted": false }, { "_id": "e9d29a9g", "boosted": true }, { "_id": "f8f2a9f6a", "boosted": false }, { "_id": "pe55z8a", "boosted": false }, { "_id": "pvazpd97", "boosted": false }, { "_id": "ft8azefze", "boosted": true }, ]
const shuffleMeSoftly = (d, size) => {
let g = d.reduce((r,c) => (r[c.boosted] = [...r[c.boosted] || [], c],r), {})
return g.false.reduce((r,c,i) => {
let nt = g.true[Math.floor(i/size)]
r = i%size == 0 ? [...r || [], ...(nt ? [nt] : []), c] : [...r || [], c]
return r
}, [])
}
console.log(shuffleMeSoftly(data, 2)) // true every 2 false
console.log(shuffleMeSoftly(data, 3)) // true every 3 false
With lodash and ES6 spread syntax you could:
const data = [ { "_id": "aze54aze", "boosted": false }, { "_id": "94v2d9e3", "boosted": false }, { "_id": "999f5a8az4", "boosted": false }, { "_id": "e9d29a9g", "boosted": true }, { "_id": "f8f2a9f6a", "boosted": false }, { "_id": "pe55z8a", "boosted": false }, { "_id": "pvazpd97", "boosted": false }, { "_id": "ft8azefze", "boosted": true }, ]
const shuffleMeSoftly = (d, size) => {
let grouped = _.groupBy(d, 'boosted')
let chunks = _.chunk(grouped.false, size)
return _.reduce(chunks, (r,c,i) => [...r, ...(grouped.true[i] ? [grouped.true[i]] : []), ...c], [])
}
console.log(shuffleMeSoftly(data, 2)) // true every 2 false
console.log(shuffleMeSoftly(data, 3)) // true every 3 false
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
By using groupBy/chunk and then reduce.
It really is 2 lines if you get the chunks
into the reduce instead of being its own variable but I left it for readability etc.
Upvotes: 1