how to transpose 2d array using javascript [duplicate] - javascript

This question already has answers here:
Transposing a 2D-array in JavaScript
(25 answers)
Closed 2 years ago.
I have an array comprising of the following data and I am using javascript to process the data
Portfolio, Value
["SFT_DEA_LXD", 17841.17]
["SFT_DEA_LXD", 69373.28]
["SFT_DEA_LXD", 28279.65]
["SFT_ISA_LXD", 10082.31]
I have run a following code to summate the values and group by Portfolio
function groupBy(array, groups, value) {
var result = [],
hash = Object.create(null);
array.forEach(function (a) {
var keys = groups.map(function (i) { return a[i] }),
key = keys.join('|');
if (!hash[key]) {
hash[key] = keys.concat(0);
result.push(hash[key]);
}
hash[key][hash[key].length - 1] += +a[value];
});
return result;
}
result = groupBy(testArray, [0], 1);
testArray is
["SFT_DEA_LXD", 115494.1]
["SFT_ISA_LXD", 10082.31]
and I need to transpose the data to the following format
["SFT_DEA_LXD", "SFT_ISA_LXD"]
[115494.1, 10082.31]
Can you advise how I can change the array to the above format to pass the data to highcharts, with thanks.
Many Thanks for any help
Colin

const testArray = [["SFT_DEA_LXD", 115494.1],
["SFT_ISA_LXD", 10082.31]];
const newArray = [];
const newArray1 = [];
testArray.forEach(item => {
newArray.push(item[0]);
newArray1.push(item[1]);
});
const result = [newArray, newArray1];

I don't understand what exactly you want to do but for transposing array its very simple and you can do it with a function or script like this
let transpose = function(arr){
let m = arr.length;
let n = arr[0].length;
let f = [];
let t = [];
for (let j=0;j<n; j++){
t = [];
for (let i=0;i<m; i++){
t.push(arr[i][j]);
}
f.push(t);
}
return f;
}
let a = [["test1",125.1] , ["test2",542.2],["test3",2.2]];
let b = transpose(a);
console.log(a);
console.log(b);

const portfolios = testData.map(([portfolio]) => portfolio);
const values = testData.map(([, value]) => value);
It's as simple as that.
'use strict';
const testData = [
["SFT_DEA_LXD", 115494.1],
["SFT_ISA_LXD", 10082.31]
];
const portfolios = testData.map(([portfolio]) => portfolio);
const values = testData.map(([, value]) => value);
console.log(portfolios); [ 'SFT_DEA_LXD', 'SFT_ISA_LXD' ]
console.log(values); [ 115494.1, 10082.31 ]

Related

how to get a cumulative total array from 3 two dimensional arrays

I have 3 two dimensional arrays as given below which are series data to plot lines on a graph with the key being the timestamp.
const arr1 = [[1641013200000,1881],[1643691600000,38993],[1646110800000,41337],[1648785600000,78856],[1651377600000,117738],[1654056000000,119869],[1656648000000,157799],[1659326400000,196752],[1662004800000,199061],[1664596800000,237034],[1667275200000,239153],[1669870800000,269967]]
const arr2 = [[1641013200000,1302],[1643691600000,3347],[1646110800000,4754],[1648785600000,6948],[1651377600000,9725],[1654056000000,11314],[1656648000000,13787],[1659326400000,16666],[1662004800000,18370],[1664596800000,20876],[1667275200000,22384],[1669870800000,23560]]
const arr3 = [[1643691600000,67350],[1648785600000,134700],[1651377600000,202148],[1654056000000,202270],[1656648000000,269843],[1659326400000,337346],[1662004800000,337470],[1664596800000,404861],[1667275200000,404889],[1669870800000,472239]]
I want to plot another series line which gives the cumulative total of all three arrays values
(Note: if a timestamp is not present in either of the arrays, add the previous index value)
const totalArray = [
[1641013200000,3183],[1643691600000, 109690],[1646110800000, 113441],[1648785600000, 220504],
[1651377600000, 329611],[1654056000000, 333453],[1656648000000, 441429],[1659326400000, 550764],
[1662004800000, 554901],[1664596800000, 662771],[1667275200000, 666426],[1669870800000, 765766]
]
I have tried this, but some values are incorrect due to the timestamp not being present in either one
Approach:
const arr1 = [
[1641013200000, 1881],
[1643691600000, 38993],
[1646110800000, 41337],
[1648785600000, 78856],
[1651377600000, 117738],
[1654056000000, 119869],
[1656648000000, 157799],
[1659326400000, 196752],
[1662004800000, 199061],
[1664596800000, 237034],
[1667275200000, 239153],
[1669870800000, 269967]
];
const arr2 = [
[1641013200000, 1302],
[1643691600000, 3347],
[1646110800000, 4754],
[1648785600000, 6948],
[1651377600000, 9725],
[1654056000000, 11314],
[1656648000000, 13787],
[1659326400000, 16666],
[1662004800000, 18370],
[1664596800000, 20876],
[1667275200000, 22384],
[1669870800000, 23560]
];
const arr3 = [
[1643691600000, 67350],
[1648785600000, 134700],
[1651377600000, 202148],
[1654056000000, 202270],
[1656648000000, 269843],
[1659326400000, 337346],
[1662004800000, 337470],
[1664596800000, 404861],
[1667275200000, 404889],
[1669870800000, 472239]
];
const calculateTotal = () => {
var ret;
for (let a3 of arr3) {
var index = arr1.map(function(el) {
return el[0];
}).indexOf(a3[0]);
console.log(index);
if (index === -1) {
ret = arr1[index][0];
console.log(ret);
}
}
let unsortedArr = arr1.concat(arr2, arr3);
var sortedArray = unsortedArr.sort((a, b) => a[0] - b[0]);
var added = addArray(sortedArray);
console.log("Curent Output: " + JSON.stringify(added));
}
const addArray = (tuples) => {
var hash = {},
keys = [];
tuples.forEach(function(tuple) {
var key = tuple[0],
value = tuple[1];
if (hash[key] === undefined) {
keys.push(key);
hash[key] = value;
} else {
hash[key] += value;
}
});
return keys.map(function(key) {
return ([key, hash[key]]);
});
}
calculateTotal();
Is it possible to achieve this?
In your code there is this:
if (index === -1) {
ret = arr1[index][0];
But that assignment will fail as arr1[-1] is not defined.
Then when you do:
let unsortedArr = arr1.concat(arr2, arr3);
...you end up with an array that does not have the knowledge to use default values (from a previous index) when any of the three arrays has a "missing" time stamp.
I would suggest this approach:
Collect all the unique timestamps (from all arrays) into a Map, and associate arrays to each of those keys: these will be empty initially.
Populate those arrays with the timestamps from the original arrays
Get the sorted list of entries from that map
Fill the "gaps" by carrying forward values to a next array when the corresponding slot is undefined. At the same time sum up these values for the final output.
Here is an implementation:
function mergeArrays(...arrays) {
const map = new Map(arrays.flatMap(arr => arr.map(([stamp]) => [stamp, []])));
arrays.forEach((arr, i) => {
for (const [timeStamp, value] of arr) {
map.get(timeStamp)[i] = value;
}
});
const state = Array(arrays.length).fill(0);
return Array.from(map).sort(([a], [b]) => a - b).map(([timeStamp, arr], i) =>
[timeStamp, state.reduce((sum, prev, j) => sum + (state[j] = arr[j] ?? prev), 0)]
);
}
// Example run
const arr1 = [[1641013200000,1881],[1643691600000,38993],[1646110800000,41337],[1648785600000,78856],[1651377600000,117738],[1654056000000,119869],[1656648000000,157799],[1659326400000,196752],[1662004800000,199061],[1664596800000,237034],[1667275200000,239153],[1669870800000,269967]];
const arr2 = [[1641013200000,1302],[1643691600000,3347],[1646110800000,4754],[1648785600000,6948],[1651377600000,9725],[1654056000000,11314],[1656648000000,13787],[1659326400000,16666],[1662004800000,18370],[1664596800000,20876],[1667275200000,22384],[1669870800000,23560]];
const arr3 = [[1643691600000,67350],[1648785600000,134700],[1651377600000,202148],[1654056000000,202270],[1656648000000,269843],[1659326400000,337346],[1662004800000,337470],[1664596800000,404861],[1667275200000,404889],[1669870800000,472239]];
const result = mergeArrays(arr1, arr2, arr3);
console.log(result);

Convert array of structured string into multi-level object in Javascript [duplicate]

This question already has answers here:
Create an object based on file path string
(3 answers)
Closed 1 year ago.
I have an array of structured strings with have connection | as a format which self-divided into levels. I want to convert it into a structured object with multiple levels.
Input:
[
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
]
Expected output:
{
clothes: {
tshirt: {
tshirt-for-kids: {},
tshirt-for-men: {
luxury-tshirt: {}
}
},
coat: {
raincoat: {}
leather-coat: {}
}
}
}
Very simple task - just enumerate the array and create the relevant object keys:
var myArray = [
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
]
var result = {}, levels, current, temp;
while(myArray.length > 0)
{
levels = myArray.pop().split('|');
temp = result;
while(levels.length > 0)
{
current = levels.shift();
if(!(current in temp)) temp[current] = {};
temp = temp[current];
}
}
console.log(result);
You could try this:
const input = [
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
];
function convertStrToObject(str, sep, obj) {
const sepIndex = str.indexOf(sep);
if (sepIndex == -1) {
obj[str] = obj[str] || {};
} else {
const key = str.substring(0, sepIndex);
obj[key] = obj[key] || {};
convertStrToObject(str.substring(sepIndex + 1), sep, obj[key]);
}
}
const all = {};
for (let i = 0; i < input.length; ++i) {
convertStrToObject(input[i], "|", all);
}
console.log(all);
Assuming you intend to collect properties, all having an empty object as leaf node.
// input
const input = [
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
];
// Here, we collect the properties
const out = {};
// map the input array, splitting each line at |
input.map(i => i.split('|'))
.filter(a => a.length > 0) // lets not entertain empty lines in input
.forEach(a => { // process each array of property names
// start at outermost level
let p = out;
// iterate properties
for(const v of a){
// create a property if it is not already there
if(!p.hasOwnProperty(v)){
p[v] = {};
}
// move to the nested level
p = p[v];
}
});
// lets see what we have created
console.log(out);
A number of solutions have been suggested already, but I'm surprised none involves reduce() - which would seem the more idiomatic solution to me.
var array = [
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
]
var object = array.reduce(function (object, element) {
var keys = element.split("|")
keys.reduce(function (nextNestedObject, key) {
if (!nextNestedObject[key]) nextNestedObject[key] = {}
return nextNestedObject[key]
}, object)
return object
}, {})
console.log(object)
One Liner With eval
Used eval to evaluate strings like the following:
'o["clothes"]??={}'
'o["clothes"]["tshirt"]??={}'
'o["clothes"]["tshirt"]["tshirt-for-kids"]??={}'
const
data = ["clothes|tshirt|tshirt-for-kids", "clothes|coat|raincoat", "clothes|coat|leather-coat", "clothes|tshirt|tshirt-for-men", "clothes|tshirt|tshirt-for-men|luxury-tshirt"],
arr = data.map((d) => d.split("|")),
res = arr.reduce((r, a) => (a.forEach((k, i) => eval(`r["${a.slice(0, i + 1).join('"]["')}"]??={}`)), r), {});
console.log(res)
One Liner Without eval
const
data = ["clothes|tshirt|tshirt-for-kids", "clothes|coat|raincoat", "clothes|coat|leather-coat","clothes|tshirt|tshirt-for-men", "clothes|tshirt|tshirt-for-men|luxury-tshirt"],
res = data.reduce((r, d) => (d.split("|").reduce((o, k) => (o[k] ??= {}, o[k]), r), r), {});
console.log(res)

Create new array with Average of same keys in an array of objects

I have an array of object as follows:
var arr=[ {"jan":2},{"jan":5},{"feb":3},{"feb":1}];
Their will be N number of objects with any combination keys jan & feb is just an example.
I need to find average of objects with similar keys so that resultant array looks like this :
var newArr=[{"jan":3.5},{"feb":2}];
Looking to achieve this without reduce method in JavaScript.
I tried to seperate out objects with similar keys so that ic an sum and average them and push in to a new aray. something like this :
arr.forEach(a=>{
console.log(Object.keys(a))
console.log(arr.filter(ar=>ar.hasOwnProperty(Object.keys(a)[0])))
})
But it creates multiple groups for same keys like this in console.
[ {"jan":2},{"jan":5} ]
[ {"jan":2},{"jan":5} ]
[ {"feb":3},{"feb":1} ]
[ {"feb":3},{"feb":1} ]
A code without using reduce . A bit length though but easy to understand
We are using two objects , one is to store the count of the keys and other is for storing the total of the keys.
result object has the average.
var arr=[ {"jan":2},{"jan":5},{"feb":3},{"feb":1}];
var count = {};
var total = {};
arr.forEach(obj => {
var key = Object.keys(obj)[0];
if(count.hasOwnProperty(key)){
count[key]=count[key]+1;
} else {
count[key]=1;
}
if(total.hasOwnProperty(key)){
total[key]=total[key]+obj[key];
} else {
total[key]=obj[key];
}
})
var result = {}
Object.keys(total).forEach(key => {
result[key] = total[key]/count[key];
})
console.log(result)
Similar to the answer above, but makes use of a map:
var arr=[ {"jan":2},{"jan":5},{"feb":3},{"feb":1}];
let map = new Map();
let keyCount = {};
arr.forEach(e => {
let key = Object.keys(e)[0];
let value = Object.values(e)[0];
if (map.get(key) !== undefined) {
map.set(key, map.get(key) + value);
keyCount[key] = keyCount[key] + 1;
} else {
map.set(key, value);
keyCount[key] = 1;
}
});
let newArr = [];
for (let e of map.entries()) {
let obj = {};
obj[e[0]] = e[1] / keyCount[e[0]];
newArr.push(obj);
}
console.log(newArr);

Extract JSON object from each file add it to the array

I have 4 links, each of them containing one, distinct JSON object. I want to fetch and then place all of them inside of the empty array.
I came up with this(I omited async/await):
let arr = [];
let iter = 0;
const FIXED_QUANTITY = 4;
while(iter < FIXED_QUANTITY) {
const res = axios.get(`/data/${iter}.json`);
arr = [...arr, res.data.body];
iter++;
}
And my question is - is it possible to make this code a bit more elegant, perhaps using higher order functions?
You could try something like this maybe?
const urls = [];
const FIXED_QUANTITY = 4;
const iter = 4;
while (iter < FIXED_QUANTITY) {
urls.push(`/data/${iter}.json`);
}
const arr = await Promise.all([...urls.map(url => axios.get(url))]).map(
res => res.data.body
);
You can use the function Array.from as follow:
let arr = Array.from({length: FIXED_QUANTITY}, async (_, iter) => (await axios.get(`/data/${iter}.json`)).data.body);
This approach generates an array with the following structure:
[{}, {}, ..., {}]

constructing two dimensional array dynamically

I have some values in JavaScript array as shown
var sampledata = {10,20,30,40};// these values would come from database later
I want to create a two dimensional array with these values.
I want to create a array as
var newData = [[0,10],[1,20],[2,30],[3,40]]
Pure JavaScript:
var newData = [];
var sampledata = [10,20,30,40];
for (var i = 0; i < sampledata.length; i++) {
newData.push([i, sampledata[i]]);
}
Using higher-order functions:
var newData = sampledata.map(function(el, i) {
return [i, el];
})
if sampledata is an array
var sampledata = [10,20,30,40]
var newData = []
jQuery.each(sampledata,function(i,data){newData.push([i,data])})

Categories

Resources