This is a much simplified version of my real problem so ideally I'm looking a simple solution without builtin functions.
I have an array:
let data = [5,5,5,5,5];
I want to start at the second item and compare it to the first. If they are the same I want to increase by one so my array looks like this:
let data = [5,6,5,5,5];
I then want to compare the next array item to all the other ones I've checked and increase by 1 if there are any the same so the array would look like this:
let data = [5,6,6,5,5];
but now there are two values the same in the values I've checked, so I want to check for similar values in the array I've already checked and add one to the item at the current array index if the current value is the same as any that have come before. 6 has been used, so I want to change the array to look like this:
let data = [5,6,7,5,5];
And so on...
I've got this, but it's not producing the result I want:
let data = [5,5,5,5,5]
const looper = () => {
for (let i=-1; i<data.length; i++) {
console.log("i", i)
for (let j=1; j<data.length; j++) {
console.log("j", j)
if (data[i] <= data[i-1] ) {
console.log("DATA", i, data[i])
data[i] += i
console.log("DATA", i, data)
looper()
} else {
continue
}
}
}
}
looper()
You could take an object and take the reference to the largest value.
function fn(array) {
const
getValue = v => {
if (v in values) return getValue(values[v]);
values[v] = v + 1;
return v;
},
values = {};
return array.map(getValue)
}
console.log(...fn([5, 5, 5, 5, 5]));
console.log(...fn([5, 5, 4, 5, 5]));
console.log(...fn([5, 5, 6, 6, 4, 4]));
Funky other data set.
function fn(array) {
const
getValue = (values = {}) => v => {
if (v in values) return getValue(values)(values[v]);
values[v] = v + 1;
return v;
};
return Object
.entries(array.reduce((r, o) => {
Object.entries(o).forEach(([k, v]) => (r[k] ??= []).push(v));
return r;
}, {}))
.map(([k, v]) =>[k, v.map(getValue())])
.reduce((r, [k, a]) => a.map((v, i) => ({ ...r[i], [k]: v })), []);
}
const
data = [{ cx: 2, cy: 3 }, { cx: 2, cy: 3 }, { cx: 2, cy: 3 }, { cx: 2, cy: 3 }, { cx: 2, cy: 3 }],
result = fn(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A slightly better approach by using only a single loop of the data and keeping the values along with the key.
const
getValue = (values = {}) => {
const
fn = (k, v) => {
const key = [k, v].join('|');
if (key in values) return fn(k, values[key]);
values[key] = v + 1;
return v;
};
return fn;
},
data = [{ cx: 2, cy: 3 }, { cx: 2, cy: 3 }, { cx: 2, cy: 3 }, { cx: 2, cy: 3 }, { cx: 2, cy: 3 }],
getFn = getValue(),
result = data.map(o => Object.fromEntries(Object
.entries(o)
.map(([k, v]) => [k, getFn(k, v)])
));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Break this down into two parts:
Part 1:
Adjust all elements in array 2 based on array 1
Part 2:
Make numbers in array 2 unique: Here you need to iterate over your array continually, until no changes are found in an iteration.
const fun = ra => {
for (let i = 1; i < ra.length; i++) {
let k = 0;
while (k < i)
ra[i] === ra[k] ? (ra[i]++, k = 0) : k++;
}
return ra;
}
console.log(...fun([3, 3, 3]));
console.log(...fun([4, 3, 3]));
console.log(...fun([4, 3, 3, 5]));
Related
At the end I get numbers, how to convert it to array?
Example:
Input: 4, 5, 1, 2, 3, -2
Output: [(13, 9, 4, 3, 1, -2)];
function sumNumbers(numbersList) {
const data = numbersList.forEach((item, index) => {
const output = numbersList.reduce(
(acc, c, i) => (index !== i ? (acc += c) : c),
0
);
console.log(result);
return output;
});
return data;
}
sumNumbers([4, 5, 1, 2, 3, -2]);
Consider replacing the Array.prototype.forEach with Array.prototype.map (since we want the value returned)
function sumNumbers(numbersList) {
const main = numbersList.map((item, index) => {
const result = numbersList.reduce(
(acc, c, i) => (index !== i ? (acc += c) : c),
0
);
return result;
});
return main;
}
console.log(sumNumbers([4, 5, 1, 2, 3, -2]))
Explanation:
.forEach returns undefined (docs)
while .map returns "A new array with each element being the result of the callback function." (docs)
The response given by #tibebes-m, an other approach (which reduces complexity) is to iterate back the array backwards, and use only a reduce function (no map)
const sumNumbers = (list) => list
.reverse()
.reduce((acc, next, index) => {
acc.unshift(next + (acc[0] || 0));
return acc;
}, []);
console.log(sumNumbers([4, 5, 1, 2, 3, -2]));
I have two objects as follows:
const a = {
'2021-1': 10,
'2021-2': 8
}
const b = {
'2021-1': 10,
'2020-3': 10,
'2020-4': 15,
'2020-5': 12,
'2020-6': 4
}
I would like to merge two objects and sum up values for duplicated keys.
Expected result is:
{
'2021-1': 20,
'2021-2': 8,
'2020-3': 10,
'2020-4': 15,
'2020-5': 12,
'2020-6': 4
}
You can perform a reduce operation over the entries of the second object to sum the values of each key, using a copy of the first object as the initial value.
const a = {
'2021-1': 10,
'2021-2': 8
}
const b = {
'2021-1': 10,
'2020-3': 10,
'2020-4': 15,
'2020-5': 12,
'2020-6': 4
}
const res = Object.entries(b).reduce((acc,[k,v])=>{
acc[k] = (acc[k] || 0) + v;
return acc;
}, {...a});
console.log(res);
This utility function merges the two objects and sums conflicting keys, including all the values unique to either a or b.
const mergeWithSum = (a, b) =>
[...Object.keys(a), ...Object.keys(b)].reduce((combined, key) => {
combined[key] = (a[key] ?? 0) + (b[key] ?? 0);
return combined;
}, {});
const a = {
'2021-1': 10,
'2021-2': 8
}
const b = {
'2021-1': 10,
'2020-3': 10,
'2020-4': 15,
'2020-5': 12,
'2020-6': 4
}
console.log(mergeWithSum(a, b));
here is another solution
function mergeObj(obja, objb) {
const merged = {...obja};
for ([key, value] of Object.entries(objb)) {
if(merged.hasOwnProperty(key)) {
merged[key] = merged[key] + value
} else {
merged[key] = value
}
}
return merged
}
it uses a simple for of loop, from object.entries and we destructure the array that contains key and value
I have an Object like this:
const val = {"abc":{"1":1, "2":6,"3":5},"def":{"1":3, "2":4,"3":8},"xyz":{"1":5, "2":6,"3":7}}
I want to transform the object data like below:
[{"abc":1,"def":3,"xyz":5},{"abc":6,"def":4,"xyz":6}, ...]
All the values are dynamic, any number of inner object may be there
I have tried like this:
const val = {"abc":{"1":1, "2":6,"3":5},"def":{"1":3, "2":4,"3":8},"xyz":{"1":5, "2":6,"3":7}}
let dataObj = {};
let secondArr = [];
let dataArr =[]
Object.entries(val).map(firstObj=>{
Object.entries(firstObj[1]).forEach(secondObj => {
dataObj={[firstObj[0]]:secondObj[1]};
secondArr.push(dataObj);
})
dataArr.push(secondArr)
})
console.log(dataArr)
Can anyone tell me a solution for this?
Thanks in advance
You could iterate the entries of the objects and take the inner keys as indices of the array with new objects with outer key and value.
var data = { abc: { 1: 1, 2: 6, 3: 5 }, def: { 1: 3, 2: 4, 3: 8 }, xyz: { 1: 5, 2: 6, 3: 7 } },
result = Object
.entries(data)
.reduce((r, [k, o]) => {
Object.entries(o).forEach(([i, v]) =>
Object.assign(r[i - 1] = r[i - 1] || {}, { [k]: v }));
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
In the below function I am attempting to get an output which resembles this:
[[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591].
I can see that the problem I have embedded is that I am always adding the temp array with a push to the functions return, as a result, all of the individual numbers apart from the last number in the for each function are being pushed into the target array with the array object also.
I feel as though I need a further conditonal check but for the life of me I am unable to come up with solution which works.
Any suggestions would be much appreciated.
const sortme = (unsortedArr)=> {
let tempArr = [];
let outputArr = [];
const reorderedArr = unsortedArr.sort((a,b) => a-b);
reorderedArr.forEach((number, i) => {
if ((i === 0) || (reorderedArr[i] === reorderedArr[i-1])) {
tempArr.push(number);
}
else {
outputArr.push(tempArr);
tempArr = [];
tempArr.push(number);
}
})
outputArr.push(tempArr[0]);
return outputArr;
}
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
sortme(unsortedArr);
i would make a deduped copy and .map() it to transform the values into arrays containing values from the original ( sorted ) array that you get using a .forEach :
const unsortedArr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
const sortMe = (arr) => {
arr = arr.sort((a, b) => a - b);
// a short way to dedupe an array
// results in : 1, 2, 4, 5, 10, 20, 391, 392, 591
let dedupe = [...new Set(arr)];
let tmpArr;
return dedupe.map(e => {
tmpArr = []; // empty tmpArr on each iteration
// for each element of the deduped array, look for matching elements in the original one and push them in the tmpArr
arr.forEach(a => {
if (a === e)
tmpArr.push(e);
})
if(tmpArr.length === 1)
return tmpArr[0]; // in case you have [4] , just return the 4
else
return tmpArr; // in case you have [1,1,1,1]
// shorthand for the if/else above
// return tmpArr.length === 1 ? tmpArr[0] : tmpArr;
});
}
const result = sortMe(unsortedArr);
console.log(result);
This should work (using reduce):
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
let lastValue = null;
var newArr = unsortedArr.sort((a,b) => a-b).reduce((acc, value) => {
if (acc.length == 0 || ((acc.length > 0 || !acc[acc.length-1].length) && lastValue !== value)) {
acc.push(value);
} else if (acc.length > 0 && lastValue === value) {
acc[acc.length-1] = (acc[acc.length-1].length ? acc[acc.length-1].concat([value]): [value, value]);
}
lastValue = value;
return acc;
}, []);
console.log(newArr);
And another approach, just for fun:
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
var arr = unsortedArr.sort((a,b) => a-b).reduce((acc, value) => {
if (acc.length > 0 && acc[acc.length-1].includes(value)) {
acc[acc.length-1].push(value);
} else {
acc.push([value])
}
return acc;
}, []).map((v) => v.length > 1 ? v: v[0]);
console.log(arr);
I hope the below one is quite simple;
function findSame(pos, sortedArr){
for(let i =pos; i<sortedArr.length; i++){
if(sortedArr[i] !== sortedArr[pos]){
return i
}
}
}
function clubSameNumbers(unsortedArr){
let sortedArr = unsortedArr.sort((a,b)=>a-b)
//[ 1, 1, 1, 1, 2, 2, 2, 4, 5, 10, 20, 20, 391, 392, 591 ]
let result = []
for(let i = 0; i < sortedArr.length; i = end){
let start = i
var end = findSame(i, sortedArr)
let arr = sortedArr.slice(i, end)
arr.length > 1 ? result.push(arr) : result.push(...arr)
}
return result
}
console.log(clubSameNumbers([1,2,4,591,392,391,2,5,10,2,1,1,1,20,20]))
//[ [ 1, 1, 1, 1 ], [ 2, 2, 2 ], 4, 5, 10, [ 20, 20 ], 391, 392, 591 ]
existingJsObj = {"a": [1,2,3,4], "b":[11,22,33,44]}
I want to convert this javascript into something that doesnt have array items in it, like below
desiredJsObj = [{"a":1, "b":11},{"a":2,"b":22},{"a":3, "b":33},{"a":4, "b":44}]
You could iterate the keys and the values while using a new array and object for the result.
var object = { a: [1, 2, 3, 4], b: [11, 22, 33, 44] },
array = Object.keys(object).reduce(function (r, k) {
object[k].forEach(function (v, i) {
(r[i] = r[i] || {})[k] = v;
});
return r;
}, []);
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would do following:
const income = {"a": [1,2,3,4], "b":[11,22,33,44]};
const res = income.a.map((a, i) => ({ a: a, b: income.b[i] }));
This works in assumption that "a" length is equal to "b" length.
try this
existingJsObj = {"a": [1,2,3,4], "b":[11,22,33,44]}
desiredJsObj = []
keys = Object.keys(existingJsObj);
existingJsObj[keys[0]].forEach((val, index) => {
value = {};
keys.forEach((key, i) => value[key] = existingJsObj[key][index])
desiredJsObj.push(value)
})