i have an incoming array:
[{step: 0, count: 1}, {step: 1, count: 5}, {step: 5, count: 5}]
so i need to transform incoming array in another array
[0, 1, 2, 3, 4, 5, 10, 15, 20, 25, 30]
I have tried to go this way:
const convertRangeData = (rangeData) =>
{
const convertedRangeData =
rangeData.reduce( (acc, item) =>
{
const { step, count } = item;
const prev = acc[acc.length - 1];
return [...acc, ...[...Array(count)].fill(step).map((i, idx) => i * (idx + 1) + prev)];
},[0] )
return convertedRangeData;
}
but I've got
[0, 0, 1, 2, 3, 4, 5, 10, 15, 20, 25, 30]
Use Array.from() to create an array with values in the ranges. Then iterate the array of ranges.
To create the continuous ranges reduce the array of ranges. When creating a range take the last number from the accumulator (acc), and use it as the start value.
const range = ({ step, count }, start = 0) =>
Array.from({ length: count }, (_, i) => (i + 1) * step + start)
const continuousRange = arr =>
arr.reduce((acc, r) => acc.concat(range(r, acc[acc.length -1])), [])
const ranges = [{step: 0, count: 1}, {step: 1, count: 5}, {step: 5, count: 5}]
const result = continuousRange(ranges)
console.log(result)
my way
const ranges = [{step: 0, count: 1}, {step: 1, count: 5}, {step: 5, count: 5}]
const convertRangeData = rangeData => rangeData.reduce((acc, {step,count}) =>
{
let prev = acc[acc.length - 1] || 0
while(count--)
acc.push(prev+=step)
return acc
},[])
console.log( convertRangeData(ranges) )
Related
I am trying this solution but it is not giving me the result I want.
I don't want to count the number of pairs of 1 cause it is not really a pair as it appears 4 times.
I need to count the "perfect" pairs, like in this case: 5 and 2. Right now this is giving me 4 as result and it should be 2.
How could I achieve that? I am stuck.
let ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2];
const countPairs = (ar) => {
let obj = {};
ar.forEach((item) => {
obj[item] = obj[item] ? obj[item] + 1 : 1;
});
return Object.values(obj).reduce((acc, curr) => {
acc += Math.floor(curr / 2);
return acc;
}, 0);
};
console.log( countPairs(ar1) )
You can filter the object values by 2 and count the list
let ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2];
const countPairs = (ar) => {
let obj = {};
ar.forEach((item) => {
obj[item] = obj[item] ? obj[item] + 1 : 1;
});
return Object.values(obj).filter(e => e == 2).length;
};
console.log(countPairs(ar1))
This can be one-liner using Map as:
const countPairs(arr) => [...arr.reduce((dict, n) => dict.set(n, (dict.get(n) ?? 0) + 1), new Map()).values(),].filter((n) => n === 2).length;
let ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2];
const countPairs = (arr) =>
[
...arr
.reduce((dict, n) => dict.set(n, (dict.get(n) ?? 0) + 1), new Map())
.values(),
].filter((n) => n === 2).length;
console.log(countPairs(ar1));
or that
const
ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2]
, countPerfectPairs = arr => arr.reduce((r,val,i,{[i+1]:next})=>
{
if(!r.counts[val])
{
r.counts[val] = arr.filter(x=>x===val).length
if (r.counts[val]===2) r.pairs++
}
return next ? r : r.pairs
},{counts:{},pairs:0})
console.log( countPerfectPairs(ar1) )
If you prefer Details:
const
ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2]
, countPerfectPairs = arr => arr.reduce((r,val)=>
{
if(!r.counts[val])
{
r.counts[val] = arr.filter(x=>x===val).length
if (r.counts[val]===2) r.pairs++
}
return r
},{counts:{},pairs:0})
console.log( countPerfectPairs(ar1) )
Say I have an array:
arr = [25, 25, 25, 20, 15, 10, 10, 5];
and I want to count up the number of duplicates (ie. three 25s and 2 10s) and make a new array that becomes:
newArr = ['25 * 3', 20, 15, '10 * 2', 5];
How should I go about doing this? Thanks!
It can be solved using Set and filter
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
const newArr = [...new Set(arr)].map((x) => {
const count = arr.filter(y => y == x).length
return count > 1 ? x + " * " + count: x;
})
console.log(newArr) // ["25 * 3", 20, 15, "10 * 2", 5]
or if you want the numeric value you can do that
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
const newArr = [...new Set(arr)].map((x) => arr.filter(y => y == x).length * x)
console.log(newArr) // [75, 20, 15, 20, 5]
You can use a Array#forEach loop to iterate through each item of the array, keeping track of how many times each item has been seen before.
Demo:
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
let result = [], seenBefore = [];
arr.forEach((item) => {
let seen = seenBefore.indexOf(item);
if (seen !== -1) return result[seen].count++;
result.push({ name: item, count: 1 });
seenBefore.push(item);
});
result = result.map(({ name, count }) =>
count > 1 ? `${name} * ${count}` : name
);
console.log(result);
The same technique but smaller using Array#reduce:
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
let result = arr
.reduce(
(acc, item) => {
acc[1].indexOf(item) !== -1 ? acc[0][acc[1].indexOf(item)].count++ : (acc[0].push({ name: item, count: 1 }), acc[1].push(item));
return acc;
},
[[], []]
)[0]
.map(({ name, count }) => (count > 1 ? `${name} * ${count}` : name));
console.log(result);
You could use reduce and check if the current element in the iteration is equal to the previous element and then also what is the type of last element added to the accumulator.
const arr = [25, 25, 25, 20, 15, 10, 10, 5];
const result = arr.reduce((r, e, i, arr) => {
if (i && e === arr[i - 1]) {
if (typeof r[r.length - 1] === 'number') {
r[r.length - 1] = `${e} * 2`;
} else {
const [key, value] = r[r.length - 1].split(' * ')
r[r.length - 1] = `${key} * ${+value + 1}`
}
} else {
r.push(e)
}
return r;
}, [])
console.log(result)
I'm trying to sum the values of arrays inside an array.
const arr = [
{ key: 0, x: [4,5,6], y: [1,2,3,4]},
{ key: 0, x: [1], y: [] }
]
The expected output would be 26 ( 4 + 5 + 6 + 1 + 2 ...)
No idea how to do this, tried with reduce but I don't know how to access the other array.
Any help would be great.
You can try getting the sum of nested object's array first, then sum them up and return like the following way:
const arr = [
{ key: 0, x: [4,5,6], y: [1,2,3,4]},
{ key: 0, x: [1], y: [] }
]
const sum = arr.reduce((a, c) => {
const cTemp = Object.values(c).flat().reduce((aa,cc) => aa+cc, 0);;
return a + cTemp;
}, 0);
console.log(sum);
const total = [
{key: 0, x: [4, 5, 6], y: [1, 2, 3, 4]},
{key: 0, x: [1], y: []},
]
.map(({x, y}) => [...x, ...y])
.reduce((total, curr) => total + curr.reduce((a, b) => a + b), 0);
const total = [
{key: 0, x: [4, 5, 6], y: [1, 2, 3, 4]},
{key: 0, x: [1], y: []},
]
.map(({x, y}) => [...x, ...y])
.reduce((total, curr) => total + curr.reduce((a, b) => a + b), 0);
console.log(total);
No idea how to do this, tried with reduce but I don't know how to
access the other array.
You can create another function named sum to sum all values in an array. After that, at each object, you can use Spread ... to merge 2 arrays into one like this.
const arr = [ { key: 0, x: [4,5,6], y: [1,2,3,4]},
{ key: 0, x: [1], y: [] }];
const sum = (arr) => arr.reduce((acc, curr) => acc+= curr, 0);
const result = arr.reduce((acc, {x, y}) => acc += sum([...x, ...y]), 0);
console.log(result);
Another way is to use Array#flatMap to get all values, then use Array#reduce to sum them.
const allValues = arr.flatMap(({x, y}) => [...x, ...y]);
const result = allValues.reduce((acc, curr) => acc+= curr, 0);
const arr = [ { key: 0, x: [4,5,6], y: [1,2,3,4]},
{ key: 0, x: [1], y: [] }];
const allValues = arr.flatMap(({x, y}) => [...x, ...y]);
const result = allValues.reduce((acc, curr) => acc+= curr, 0);
console.log(result);
The flatMap() method returns a new array formed by applying a given
callback function to each element of the array, and then flattening
the result by one level
This works for me.
const arr = [{
key: 0,
x: [4, 5, 6],
y: [1, 2, 3, 4]
},
{
key: 0,
x: [1],
y: []
}
]
var total = 0;
arr.forEach(function(value) {
value.x.forEach(function(x) {
total += x;
});
value.y.forEach(function(y) {
total += y;
});
});
console.log(total);
im trying to add counting number for duplicate in JS.
and i am completely stack in this case below.
i need to compare objects with two value (x, y) and if there are same values of (x, y) add count 1 on new objects.
is there any way to convert data to newData such as below?
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const newData = [
{x: 1, y:1 ,count:2}
{x: 2, y:2 ,count:1}
]
use .reduce() function
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const output = data.reduce((acc, curr) => {
curr.count = 1;
const exists = acc.find(o => o.x === curr.x && o.y === curr.y);
exists ? exists.count++ : acc.push(({ x, y, count } = curr));
return acc;
}, []);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One way of doing so, is to create a map with the x and y values, and increment the count accordingly, then convert the map into an array:
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const makeXYMap = (data) => data.reduce((acc, cur) => {
const { x, y } = cur;
const entry = acc[`${x}_${y}`];
if (entry) {
acc[`${x}_${y}`] = {...entry, count: entry.count + 1};
} else {
acc[`${x}_${y}`] = { x, y, count: 1 };
}
return acc;
}, {});
const makeArray = (XYMap) => Object.values(XYMap);
console.log(makeArray(makeXYMap(data)));
Note that complexity wise, this solution is a O(N).
https://jsfiddle.net/9o35neg7/
const data = [
{ id: 1, x: 1, y: 1 },
{ id: 2, x: 2, y: 2 },
{ id: 3, x: 1, y: 1 },
// .. so on ..
];
const countedData = data.reduce((acc, { x, y }, index, array) => {
acc[`x${x}y${y}`] = {
x,
y,
count: (acc[`x${x}y${y}`] ? acc[`x${x}y${y}`].count : 0) + 1
};
return index === (array.length - 1) ? Object.values(acc) : acc;
}, {});
console.log(countedData);
Use forEach and build an object with key (made of x, y) and values (aggregate count). Get the Object.values to get the results as array.
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const counts = (arr, res = {}) => {
arr.forEach(({x , y}) =>
res[`${x}-${y}`] = { x, y, count: (res[`${x}-${y}`]?.count ?? 0) + 1 })
return Object.values(res);
}
console.log(counts(data))
I have an array of objects, i need to split this array to multiple arrays. If sum of element count <= 500, return these objects in array.
const array = [{idx: 1, count: 100}, {idx: 2, count: 200}, {idx: 3, count: 200}, {idx: 4, count: 100}]
//Expected Result: array of arrays
// [[{idx: 1, count: 100}, {idx: 2, count: 200}, {idx: 3, count: 200}], [{idx: 4, count: 100}]]
You can simply do it using reduce:
const array = [{idx: 1, count: 100}, {idx: 2, count: 200}, {idx: 3, count: 200}, {idx: 4, count: 100}]
const result = array.reduce((carry, item) => {
if (!carry.array.length || carry.count + item.count > 500) {
carry.array.push([item]);
carry.count = item.count;
} else {
carry.array[carry.array.length - 1].push(item);
carry.count += item.count;
}
return carry;
}, {array: [], count: 0}).array;
console.log(result);
This can be solved quite elegantly with generators:
function* groupTill(arr, predicate) {
let acc = [], pred = predicate();
for(const el of arr) {
if(!pred(el)) {
yield acc; acc = []; pred = predicate();
}
acc.push(el);
}
yield acc;
}
const result = [...groupTill(input, (total = 0) => ({ count }) => (total += count) < 500)];
You can use forEach to iterate through array and have two separate variables. One for the result array and another to hold the sum of count
const array = [{idx: 1, count: 100}, {idx: 2, count: 200}, {idx: 3, count: 200}, {idx: 4, count: 100}]
const res = [[]]; //initialize the result array with initial subarray
let count = 0; //initialize the count to zero
//Loop through the elements of array.
array.forEach(x => {
res[res.length - 1].push(x); //Add the the current element to the last sub array
count += x.count //increase the temporary count
//if count exceeds 500
if(count >= 500){
//add another sub array to the end of final array
res.push([]);
//Reset the count to 0
count = 0;
}
});
console.log(res);
You can use reduce with flags ( These are used to track whether we need to increase the index or not )
const array = [{idx: 1, count: 100}, {idx: 2, count: 200}, {idx: 3, count: 200}, {idx: 4, count: 100}]
let splitter = (arr) => {
let index = 0,
total = 0
return arr.reduce((op, inp) => {
if ((total + inp.count) > 500) {
index++;
total = 0;
}
total += inp.count
op[index] = op[index] || []
op[index].push(inp)
return op
}, [])
}
console.log(splitter(array))