I have an array:
array = {
"data": [
{ "value": [ 100, 13, 16 ] },
{ "value": [ 101, 14, 17 ] },
{ "value": [ 12, 15, 18 ] }
]
}
Which I am reformatting into a new array of just the columns:
const columnArray = jsonData.map( (current, index, arr) => {
let out = [];
for( let i = 0; i < current.value.length; i++ ) {
out.push( arr[ i ].value[ index ] );
}
return out;
});
// output
[
[ 100, 101, 12 ],
[ 13, 14, 15 ],
[ 16, 17, 18 ]
]
How would I re-write the columnArray mapping to do the column array and be able to sum from the previous value?
So the intended output from the original array would be:
[
[ 100, 201, 213 ],
[ 13, 27, 42 ],
[ 16, 33, 51 ]
]
I would also like the summing to be scalable (though it will always be in a 1:1 ratio). So if the data has 20 items, then each value will have 20 integers in that array too.
I have tried looping through but that didn't work as I only sum from the previous, not all the previous. And this wouldn't scale either:
const columnArray = jsonData.map( (current, index, arr) => {
let out = [];
for( let i = 0; i < current.value.length; i++ ) {
// dont touch first
if( i < 1 ) {
out.push( arr[ i ].value[ index ] );
} else {
out.push( arr[ i ].value[ index ] + arr[ i - 1 ].value[ index ] )
}
}
return out;
});
Instead of pushing the array element, add it to a variable accumulating the running totals, and push that.
const jsonData = [{
"value": [100, 13, 16]
},
{
"value": [101, 14, 17]
},
{
"value": [12, 15, 18]
}
];
const columnArray = jsonData.map((current, index, arr) => {
let out = [];
let total = 0;
for (let i = 0; i < current.value.length; i++) {
total += arr[i].value[index]
out.push(total);
}
return out;
});
console.log(columnArray);
or with a nested map():
const jsonData = [{
"value": [100, 13, 16]
},
{
"value": [101, 14, 17]
},
{
"value": [12, 15, 18]
}
];
const columnArray = jsonData.map((current, index, arr) => {
let total = 0;
return arr.map(el => total += el.value[index])
});
console.log(columnArray);
You're thinking this in the wrong way. You're storing the sum in the list, not anywhere else. So even tho your index is increasing, the resulting sum resides in the list, so to achieve your goal you have to save it in some variable then push the variable into the final list. Follow this code below:
const columnArray = array.data.map((current, index, arr) => {
let out = [];
let temp;
for (let i = 0; i < current.value.length; i++) {
// dont touch first
if (i < 1) {
temp = arr[i].value[index];
out.push(arr[i].value[index]);
} else {
temp = arr[i].value[index] + temp;
out.push(temp);
}
}
return out;
});
something like that...
const array0 = {
"data": [
{ "value": [ 100, 13, 16 ] },
{ "value": [ 101, 14, 17 ] },
{ "value": [ 12, 15, 18 ] }
]
}
const
rowCount = array0.data.reduce((c,{value})=>Math.max(c,value.length) ,0)
, arrResult = Array(rowCount).fill(0).map(x=>Array(array0.data.length).fill(0))
;
arrResult.forEach((_,i,arr)=>
{
array0.data[i].value.forEach((v,j)=>
{
arr[j][i] = v + (i? arr[j][i-1] : 0 )
})
})
console.log( arrResult)
.as-console-wrapper {max-height: 100%!important;top:0}
Related
I am practising on code wars and am currently stuck on a kyu 8 question, all the tests seem to pass bar the last one. I will add my code and the tests below plus the output I get below.
function sumArray(array) {
if (array == null || array.length <= 2) {
return 0
} else {
let largestInt = Math.max.apply(null, array)
let smallestInt = Math.min.apply(null, array)
let indexSmallest = array.indexOf(largestInt)
let indexLargest = array.indexOf(smallestInt)
array.splice(indexSmallest, 1)
array.splice(indexLargest, 1)
let sum = 0
for (let i = 0; i < array.length; i++) {
sum += array[I]
}
return sum
}
}
The tests:
const {
assert
} = require("chai");
it("example tests", () => {
assert.strictEqual(sumArray(null), 0);
assert.strictEqual(sumArray([]), 0);
assert.strictEqual(sumArray([3]), 0);
assert.strictEqual(sumArray([3, 5]), 0);
assert.strictEqual(sumArray([6, 2, 1, 8, 10]), 16);
assert.strictEqual(sumArray([0, 1, 6, 10, 10]), 17);
assert.strictEqual(sumArray([-6, -20, -1, -10, -12]), -28);
assert.strictEqual(sumArray([-6, 20, -1, 10, -13]), 3);
});
The output:
Test Results:
example tests
expected -10 to equal 3
function total(array) {
// always assure at least an empty array.
array = Array.from(array ?? []);
// sort array values ascending.
array.sort((a, b) => a - b);
array.pop(); // remove last/higest value.
array.shift(); // remove first/lowest value.
// for any to be reduced/summed-up (empty) array
// the initial value of zero always assures the
// minimum expected result of zero.
return array
.reduce((total, value) => total + value, 0);
}
const testEntries = [
[ null, 0 ],
[ [ ], 0 ],
[ [ 3 ], 0 ],
[ [ 3, 5 ], 0 ],
[ [ 6, 2, 1, 8, 10 ], 16 ],
[ [ 0, 1, 6, 10, 10 ], 17 ],
[ [ -6, -20, -1, -10, -12 ], -28 ],
[ [ -6, 20, -1, 10, -13 ], 3 ],
];
console.log(
testEntries
.map(([value, result]) =>
`(total([${ value }]) === ${ result }) ... ${ total(value) === result }`
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
I had JSON data that came back with single int values. With some changes, the values are now coming back as arrays of ints (as well as the original format).
{
"value": 10,
"value": 70,
"value": 30,
"value": 200
}
- and -
{
"value": [64, 13, 55, 34, 52, 43, 59, 20, 20],
"value": [10, 90, 20, 80, 30, 70, 60, 40, 50]
}
I had a formula that would return the min, max, and sum of the old version of JSON data. Now it doesn't work, and I can't figure out what would be the best way to re-write the function to handle the arrays. Or if its better to make a second function to handle just arrays and do a check if it is an int or array?
Is there a way that would return (from the numbers above):
// no value array, apply to all
[ 10, 200, 310 ] // min, max, sum
- and -
// for each of the value arrays
[ 23, 64, 360 ] // val 1 - min, max, sum
[ 10, 90, 450 ] // val 2 - min, max, sum
// input data
const value = document.querySelectorAll( "div" ).forEach( el => {
const contents = el.textContent, // get the text in the <div>
json = JSON.parse( contents ), // parse the data
jsonData = json.data; // get the data only
// normalise the data
// #from: https://stackoverflow.com/a/67294607/1086990
const normaliseData = arr => {
const data = arr.map(({ value }) => value);
return typeof arr[0].value === 'number' ? [data] : data;
};
// add into const
const valueArray = normaliseData( jsonData );
// get the min / max / sum
const minMaxSum = valueArray.forEach( e => {
return [
Math.min(...e),
Math.max(...e),
[...e].reduce((v, w) => v + w)
];
});
// output
console.log( minMaxSum );
});
<div>
{ "data": [ { "value": [64, 23, 45, 34, 52, 43, 59, 40] }, { "value": [10, 90, 20, 80, 30, 70, 60, 40, 50] } ] }
</div>
<div>
{ "data": [ { "value": 600 }, { "value": 70 }, { "value": 30 } ] }
</div>
Normalize the data by testing the type of the value of the first object in each array:
const valueInArray = [{ value: [64, 23] }, { value: [45, 34] }];
const valueAsSingle = [{ value: 600 }, { value: 70 }];
const normalizeData = arr => {
const data = arr.map(({ value }) => value);
return typeof arr[0].value === 'number'
? [data]
: data;
};
console.log(normalizeData(valueInArray));
//=> [ [ 64, 23 ], [ 45, 34 ] ]
console.log(normalizeData(valueAsSingle));
//=> [ [ 600, 70 ] ]
Now they are the same shape, and so you can treat them equally.
You can use Math.max and Math.min to find the maximum and minimum of the array then assign the values in the specific variables.
Currently, when you are using val.value it is consisting of the whole array and hence you also need to iterate over the array to find the max, min, or sum.
To find the sum use reduce on the val.value array and then add it in the acc[2].
// input data
const valueInArray = document.getElementById("valueInArray").innerHTML,
valueAsSingle = document.getElementById("valueAsSingle").innerHTML;
// parse
const jsonArray = JSON.parse( valueInArray ),
jsonNumber = JSON.parse( valueAsSingle ),
jsonArrayData = jsonArray.data,
jsonNumberData = jsonNumber.data;
// get numbers
const minMaxSumArray = jsonArrayData.reduce( ( acc, val ) => {
// smallest number
acc[0] = (
( acc[0] === undefined || Math.min(...val.value) < acc[0] ) ?
Math.min(...val.value) : acc[0]
)
// largest number
acc[1] = (
( acc[1] === undefined || Math.max(...val.value) > acc[1] ) ?
Math.max(...val.value) : acc[1]
)
// sum of numbers
acc[2] = (
acc[2] === undefined ?
val.value.reduce((v, w) => v + w) : val.value.reduce((v, w) => v + w) + acc[2]
)
console.log('answer', acc)
// return the array
return acc;
}, [] );
<div id="valueInArray">
{ "data": [ { "value": [64, 23, 45, 34, 52, 43, 59, 40] }, { "value": [10, 90, 20, 80, 30, 70, 60, 40, 50] } ] }
</div>
<div id="valueAsSingle">
{ "data": [ { "value": 10 }, { "value": 70 }, { "value": 30 } ] }
</div>
My take on it: first, create a single Array of all values (either arrays or single) by concatening them and using Array.flat() to flatten it. Then use a reducer to determine the sum and use Math.min/max for the min and max values.
// input data
const valuesInArray = JSON.parse(
document.querySelector("#valueInArray").textContent).data;
const singleValues = JSON.parse(
document.querySelector("#valueAsSingle").textContent).data;
// get all values from the objects to a single Array of values
// (so: convert all to single values)
const allValues = valuesInArray.map( v => v.value )
.concat(singleValues.reduce( (acc, val) => [...acc, +val.value], [] ) )
.flat();
// let's see what we have
console.log(`All values from both objects: ${JSON.stringify(allValues)}`);
// create sum, min and max
const [ sum, min, max, ] = [
allValues.reduce( (a, v) => a + +v, 0),
Math.min(...allValues),
Math.max(...allValues) ];
console.log(`From all values sum is ${sum}, min ${min} and max ${max}`);
div {
display: none;
}
<div id="valueInArray">
{ "data": [
{ "value": [64, 23, 45, 34, 52, 43, 59, 40] },
{ "value": [10, 90, 20, 80, 30, 70, 60, 40, 50] } ]
}
</div>
<div id="valueAsSingle">
{ "data":
[ { "value": 10 }, { "value": 70 }, { "value": 30 } ]
}
</div>
The second snippet aggregates data per value, where the single values are added as a values array to valuesInArray.
// input data
const valuesInArray = JSON.parse(
document.querySelector("#valueInArray").textContent).data;
const singleValues = JSON.parse(
document.querySelector("#valueAsSingle").textContent).data;
// create sum, min and max *per value*, in one go
const aggregatesAdded = valuesInArray
.concat({ value: singleValues.reduce( (acc, val) => [...acc, +val.value], [] ) } )
.reduce( (acc, val) => [...acc, {...val, aggregatedValues: {
sum: val.value.reduce( (a, v) => a + +v, 0 ),
min: Math.min(...val.value),
max: Math.max(...val.value) } }
], [])
document.querySelector("pre").textContent =
JSON.stringify({data: aggregatesAdded}, null, 2);
div {
display: none;
}
<div id="valueInArray">
{ "data": [
{ "value": [64, 23, 45, 34, 52, 43, 59, 40] },
{ "value": [10, 90, 20, 80, 30, 70, 60, 40, 50] } ]
}
</div>
<div id="valueAsSingle">
{ "data":
[ { "value": 10 }, { "value": 70 }, { "value": 30 } ]
}
</div>
<pre id="result"></pre>
I have a data object like this:
{
"backgroundColor": [
"#E5700F",
"#DA830F",
],
"data": [
26,
10,
],
}
I want to change the format to be like this:
[
{
"backgroundColor": "#E5700F",
"data": 26,},
{
"backgroundColor": "#DA830F",
"data": 10,},
]
how to achieve it using javascript?
You could do this:
const old = {
backgroundColor: ["#E5700F", "#DA830F"],
data: [26, 10],
};
let newArray = [];
old.backgroundColor.forEach((item, idx) => {
newArray.push({ backgroundColor: item, data: old.data[idx] });
});
This could work if the object is not dynamic.
let data = {
"backgroundColor": [
"#E5700F",
"#DA830F",
],
"data": [
26,
10,
],
};
let result = data.backgroundColor.map(function(item, index) {
return {
backgroundColor: item,
data: data.data[index]
}
});
console.log(result);
You can do it like this:
Note that the array's length may not be equal, so it is best to consider this in your data conversion routine.
let sourceData = {
"backgroundColor": [
"#E5700F",
"#DA830F",
],
"data": [
26,
10,
],
};
let result = [];
let length = Math.max(sourceData.backgroundColor.length, sourceData.data.length);
for (let index = 0; index < length; index++) {
result.push({
"backgroundColor": sourceData.backgroundColor[index],
"data": sourceData.data[index]
})
}
console.log(result);
I have two javascript array
let a=[{id:1},{id:2},{id:3}];
let b=[{count:35, name:'test', age:12}, {count:45 name:'test2', age:9}];
and two array push into i need final Array format is
[{count:35,name:'test', age,12, id:1} , {count:35, name:'test', age:12,id:2},{count:35, name:'test', age:12,id:3},{count:45,name:'test', age,9, id:1} , {count:45, name:'test', age:9,id:2},{count:45, name:'test', age:9,id:3} ]
And i trying
for ( var index=0; index<b.length; index++ ) {
for ( var j=0; j<a.length; j++ ) {
for (const [key, value] of Object.entries(a[j])) {
//if(j==index)
b[index][key]=value;
k[j]=b[index];
}
console.log( b[index]);
c.push(b[index]);
}
}
console.log(c);
and it shows final value is
please any body help to fix the problem
Your current implementation, is essentially updating the same b objects over and over, x number of times, changing their IDs each time through, ending at 3.
You need to "clone" the objects, so they are separate objects, like so:
let p = []; // Permutations
let a = [{id:1},{id:2}]; // Renditions...
// Presets...
let b = [{count:35, name:'test', age:12}, {count:45, name:'test2', age:9}];
// for each Rendition
a.forEach(function(a) {
// for each Preset
b.forEach(function(b){
// generate Permutation and Clone, object of b with additional id prop
p.push(Object.assign({id: a.id}, b)); // <-- Cloned here...
});
});
console.log(p)
for the sake of clarity, you might consider changing the id prop to grouping or group or group_id.
You could use flatMap:
let a=[{id:1},{id:2},{id:3}];
let b=[{count:35, name:'test', age:12}, {count:45, name:'test2', age:9}];
let m = b.flatMap(itemB => a.map(itemA => ({...itemB, ...itemA })))
console.log(m);
I got your problem. The thing is that you are mutating the same b object every iteration, that's why in the end you get id = 3 for every element. You can use a deep copy of b in each cycle, and the error should be gone.
Here's one way to deep clone, not the most efficient but it is very clear:
const bCopy = JSON.parse(JSON.stringify(b[index]));
for (const [key, value] of Object.entries(a[j])) {
//if(j==index)
bCopy[key]=value;
k[j]=bCopy; // what's this for?
}
console.log(bCopy);
c.push(bCopy);
Reduce b and for each item b1, reduce a. When reducing a, just assign both b1 and a1 to a new object.
const expectedValue = JSON.stringify(JSON.parse(
document.getElementById('expected').value))
let a = [
{ id: 1 },
{ id: 2 },
{ id: 3 }
]
let b = [
{ count: 35, name: 'test', age: 12 },
{ count: 45, name: 'test2', age: 9 }
]
let c = b.reduce((res, b1) =>
a.reduce((res1, a1) =>
[...res1, Object.assign({}, b1, a1)], res), [])
console.log(JSON.stringify(c) === expectedValue)
.as-console-wrapper { top: 0; max-height: 100% !important; }
#expected { display: none; }
<textarea id="expected">
[
{ "count": 35, "name": "test", "age": 12, "id": 1 },
{ "count": 35, "name": "test", "age": 12, "id": 2 },
{ "count": 35, "name": "test", "age": 12, "id": 3 },
{ "count": 45, "name": "test2", "age": 9, "id": 1 },
{ "count": 45, "name": "test2", "age": 9, "id": 2 },
{ "count": 45, "name": "test2", "age": 9, "id": 3 }
]
</textarea>
Try this changes.
let a=[{id:1},{id:2},{id:3}];
let b=[{count:35, name:'test', age:12}, {count:45, name:'test2', age:9}];
let c=[];
for ( var index=0; index<b.length; index++ ) {
for ( var j=0; j<a.length; j++ ) {
var obj=b[index];
for (const [key, value] of Object.entries(a[j])) {
obj[key]=value;
}
c.push(obj);
}
}
console.log(c);
I am having two array like this,
let array1 = [
{
"id": 23,
"name": "Telangana",
}
]
Here i need to update array2 color value inside properties based on array1 numberOfProjects value inside latestMetric. As u can see that in both arrays stateId and id are same.If numberOfProjects value is in the range 1 - 1000. I need to update the color value as 1. then numberOfProjects value is in the range 1000 - 2000. I need to update the color value as 2.so on. I dont know how to achieve this. I tried to map those two arrays and can able to get the ID's.But i dont know how to compare them and update the value . Pleas help me.Thanks in advance
You can do like this
let updatedArr2 = [];
function updateArr2(arr2values, colorValue) {
let updatedProperties = { ...arr2values.properties, color: colorValue };
arr2values.properties = updatedProperties;
updatedArr2.push(arr2values);
}
array2.map(arr2values =>
array1.map(arr1values => {
if (arr2values.properties.stateId === arr1values.latestMetric.stateId) {
if (
arr1values.latestMetric.numberOfProjects >= 1 &&
arr1values.latestMetric.numberOfProjects <= 1000
) {
updateArr2(arr2values, 1);
} else if (
arr2values.latestMetric.numberOfProjects >= 1000 &&
arr2values.latestMetric.numberOfProjects <= 2000
) {
updateArr2(arr2values, 2);
}
}
})
);
console.log(updatedArr2);
You could loop through each object in array1 and then check if there's any object in array2 that matches the stateId, if so, then check the number of projects in the array1 object and change the color of the object in array2 that has the same stateId, something like:
array1.forEach((o) => {
let matches = array2.filter(
(o2) => o2.properties.stateId === o.latestMetric.stateId
);
let projects = o.latestMetric.numberOfProjects;
for (let match of matches) {
if (projects > 1 && projects < 1000) {
match.properties.color = 1;
} else if (projects >= 1000 && projects < 2000) {
match.properties.color = 2;
}
}
});
let array1 = [
{
id: 23,
name: "Telangana",
code: "lnn",
regionId: 1,
isActive: true,
latitude: 17.8495919,
longitude: 79.1151663,
latestMetric: {
stateId: 23,
year: 0,
constructionValueInMn: 84623,
constructionAreaInMnSqft: 32,
numberOfProjects: 406,
noOfCompletedProjects: 19,
noOfOngoingProjects: 387,
noOfUpcomingProjects: 0,
growthRate: 0,
averagePricePerSqftInRs: 0,
totalAreaInMnSqft: 71,
overAllAvgSqft: 0,
eachVariantAvgSqft: 0,
noOfTypeOfVariant: 0,
projectCompletionCycle: 0,
},
createdAt: "2020-04-21T00:35:11.684134",
updatedAt: "2020-04-21T00:35:11.684134",
},
];
let array2 = [
{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [
[
[77.19721, 28.861519],
[77.203836, 28.86004],
],
],
},
properties: {
cartodb_id: 26,
state_code: 7,
st_nm: "NCT of Delhi",
color: 2,
id: 23,
stateId: 23,
},
},
];
array1.forEach((o) => {
let matches = array2.filter(
(o2) => o2.properties.stateId === o.latestMetric.stateId
);
let projects = o.latestMetric.numberOfProjects;
for (let match of matches) {
if (projects > 1 && projects < 1000) {
match.properties.color = 1;
} else if (projects >= 1000 && projects < 2000) {
match.properties.color = 2;
}
}
});
console.log(array2);
Try this:
array2.map(arr2 => {
//Find to return the position when the id's are the same
const arr1 = array1.find(arr => arr.latestMetric.stateId == arr2.properties.id)
// If find was successful, do this
if (arr1) {
// Destructuring assignment to be easier to compare
const { numberOfProjects } = arr1.latestMetric
if (numberOfProjects >= 1 && numberOfProjects < 1000)
arr2.properties.color = 1
else if (numberOfProjects >= 1000 && numberOfProjects < 2000)
arr2.properties.color = 2
}
})