Given the code below, how can I have item name "C" appear in the 3rd position correctly?
const foo = [
{
name: 'a',
},
{
name: 'b'
}
]
const bar = [
{
name: 'c',
position: [1, 3]
},
{
name: 'd',
position: [2]
}
]
bar.forEach((item) => {
item.position.forEach((pos) => {
foo.splice(pos - 1, 0, item);
});
})
console.log(foo);
Output
[
{ name: 'c', position: [ 1, 3 ] },
{ name: 'd', position: [ 2 ] },
{ name: 'a' },
{ name: 'c', position: [ 1, 3 ] },
{ name: 'b' }
]
Desired output
[
{ name: 'c', position: [ 1, 3 ] },
{ name: 'd', position: [ 2 ] },
{ name: 'c', position: [ 1, 3 ] },
{ name: 'a' },
{ name: 'b' }
]
You can sort all of the objects to insert by their index before adding them sequentially.
const foo = [
{
name: 'a',
},
{
name: 'b'
}
];
const bar = [
{
name: 'c',
position: [1, 3]
},
{
name: 'd',
position: [2]
}
]
bar.flatMap(x => x.position.map(p => [p, x]))
.sort(([p1], [p2]) => p1 - p2).forEach(([p, o]) => foo.splice(p - 1, 0, o));
console.log(JSON.stringify(foo));
You could build a temporary array with the wanted indices and splice with order.
const
foo = [{ name: 'a' }, { name: 'b' }],
bar = [{ name: 'c', position: [1, 3] }, { name: 'd', position: [2] }];
bar
.reduce((r, item) => {
item.position.forEach(pos => r[pos - 1] = item);
return r;
}, [])
.forEach((item, i) => foo.splice(i, 0, item));
console.log(foo);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
Given an array in the format of levels and their immediate children store in a consecutive array return a n-ary tree
Given Input format :
[{'name':'a', 'level': -1},
{'name':'b', 'level': 0},
{'name':'c', 'level': 1},
{'name':'d', 'level': 2},
{'name':'e', 'level': 0},
{'name':'f', 'level': 1},
{'name':'g', 'level': 0}
];
Expected Output should be in the below format:
[
{
name:"a",
level:-1,
children: [
{
name:"b",
level:0,
children: [
{
name:"c",
level:1,
children: [
{
name:"d",
level:2,
children: [ ]
}
]
}
]
}
],
},
{
name:"e",
level:1,
children: [
{
name:"f",
level:2,
children: [ ]
}
]
},
{
name:"g",
level:2,
children: [ ]
}
]
The recursive solution I tried to implement which failed
Above code returns
function treeTraversal(arr, index) {
if (arr === null || arr.length === 0 || index === arr.length) {
return;
}
let result = [];
let children = [];
if (arr[index - 1].level + 1 === arr[index].level) {
children.push(arr[index]);
console.log(children);
treeTraversal(arr, index + 1);
}
arr[index - 1].children = children;
result.push(arr[index - 1]);
return result;
}
const arr = [{
'name': 'a',
'level': -1
},
{
'name': 'b',
'level': 0
},
{
'name': 'c',
'level': 1
},
{
'name': 'd',
'level': 2
},
{
'name': 'e',
'level': 0
},
{
'name': 'f',
'level': 1
},
{
'name': 'g',
'level': 0
}
];
console.log(treeTraversal(arr, 1));
unexpected results. Please let me know what's wrong with the above code
You could take a helper array for the levels and assign the object to the latest array of the level plus one.
var data = [{ name: 'a', level: -1 }, { name: 'b', level: 0 }, { name: 'c', level: 1 }, { name: 'd', level: 2 }, { name: 'e', level: 0 }, { name: 'f', level: 1 }, { name: 'g', level: 0 }],
tree = [],
levels = [tree];
data.forEach(o => levels[o.level + 1].push({ ...o, children: levels[o.level + 2] = [] }));
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I'm a bit stuck with something implying recursion. I am receiving data
from an API. It looks like this:
const input = [
{ id: 'a', level: 0 },
{ id: 'b', level: 1 },
{ id: 'c', level: 1 },
{ id: 'd', level: 2 },
{ id: 'e', level: 1 },
{ id: 'f', level: 0 },
];
and I need something like
const out = [
{ id: 'a', nodes: [
{ id: 'b', nodes: [] },
{ id: 'c', nodes: [
{ id: 'd', nodes: [] },
] },
{ id: 'e', nodes: [] },
] },
{ id: 'f', nodes: [] },
];
How would you achieve that in an elegant way such as out = f(input) ?
I feel we can do a recursive nest method through a reduce but I did not manage to get it right :)
Thanks in advance!
You could use a helper array for the levels with the latest array/nodes property from the object.
const
input = [{ id: 'a', level: 0 }, { id: 'b', level: 1 }, { id: 'c', level: 1 }, { id: 'd', level: 2 }, { id: 'e', level: 1 }, { id: 'f', level: 0 }],
result = [],
levels = [result];
input.forEach(({ id, level }) =>
levels[level].push({ id, nodes: levels[level + 1] = [] })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You may try out like,
function makeObject(id){
return { id: id, nodes:[] };
}
function addObjectToNodes(array, id, node){
array.map(a => {
if(a.id === id)
a.nodes.push(node);
});
}
const nodes = [];
nodes.push(makeObject('a'));
nodes.push(makeObject('f'));
addObjectToNodes(nodes, 'a', makeObject('b'));
addObjectToNodes(nodes, 'a', makeObject('c'));
addObjectToNodes(nodes, 'a', makeObject('d'));
addObjectToNodes(nodes, 'a', makeObject('e'));
console.log(nodes);
I have several arrays like that I'm getting from a web service:
const a = [ { label: 'A', value: 100 }, { label: 'B', value: 200 } ];
const b = [ { label: 'A', value: 50 }, { label: 'B', value: 300 } ];
const c = [ { label: 'A', value: 20 }, { label: 'B', value: 130 } ];
const d = [ { label: 'A', value: 10 }, { label: 'B', value: 25 } ];
and I would like to have something like that (in a React state):
[
{ label: 'A', a: 100, b: 50, c: 20, d: 10 },
{ label: 'B', a: 200, b: 300, c: 130, d: 25 }
]
using modern JavaScript, I guess with map and reduce
EDIT:
I was not clear at all at first. I want to update my state when I get new data.
if my current state is:
[
{ label: 'A', a: 100, b: 50, c: 20, d: 10 },
{ label: 'B', a: 200, b: 300, c: 130, d: 25 }
]
and I'm getting
{ title: "a", values: [ { label: 'A', value: 12 }, { label: 'B', value: 13 } ] };
I want to update my state to
[
{ label: 'A', a: 12, b: 50, c: 20, d: 10 },
{ label: 'B', a: 13, b: 300, c: 130, d: 25 }
]
my best attempts was:
myFunction().then(data => {
const {chartData} = this.state;
chartData[data.title] = Object.keys(data.values).map(key => ({
label: chartData[data.title] || data.values[key].label,
[data.title]: data.values[key].value,
...chartData[data.title]
});
this.setState({chartData});
})
You could iterate the given state array, look for an item with the wanted label and update the properties.
function update(state, { title, values }) {
return values.reduce((r, { label, value }) => {
var temp = r.find(o => o.label === label);
if (!temp) r.push(temp = { label });
Object.assign(temp, { [title]: value });
return r;
}, state);
}
var state = [{ label: 'A', a: 100, b: 50, c: 20, d: 10 }, { label: 'B', a: 200, b: 300, c: 130, d: 25 }],
data = { title: "a", values: [{ label: 'A', value: 12 }, { label: 'B', value: 13 }] };
update(state, data);
console.log(state);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const glue = (label, ...vars) => ([].concat(vars).filter(i => i.label === label).reduce((agg, i) => ({ ...agg, ...i }), {}));
where
glue('A', [a,b,c,d]);
glue('B', [a,b,c,d]);
// .. and so on
`
Create an object with all the arrays using Shorthand property names (The key names are required to create the properties in the output. You could add more arrays to this object). Then reduce the entries returned by Object.entries()
const a = [ { label: 'A', value: 100 }, { label: 'B', value: 200 } ];
const b = [ { label: 'A', value: 50 }, { label: 'B', value: 300 } ];
const c = [ { label: 'A', value: 20 }, { label: 'B', value: 130 } ];
const d = [ { label: 'A', value: 10 }, { label: 'B', value: 25 } ];
const input = { a, b, c, d };
const merged = Object.entries(input).reduce((r, [key, arr]) => {
arr.forEach(({label, value}) => {
r[label] = r[label] || { label };
r[label][key] = value;
})
return r;
}, {})
console.log(Object.values(merged))
Here idea is
Combine all the values in one array
Use a array to keep alphabets
Loop over combined array and for each element in combined array add vales to labels and alphabet based as per index of combined array
const a = [{ label: 'A', value: 100 }, { label: 'B', value: 200 }];
const b = [{ label: 'A', value: 50 }, { label: 'B', value: 300 }];
const c = [{ label: 'A', value: 20 }, { label: 'B', value: 130 }];
const d = [{ label: 'A', value: 10 }, { label: 'B', value: 25 }];
let alpha = [...'abcdefghijklmnopqrstuvwxyz']
let combine = [a,b,c,d]
let op = combine.reduce((op,inp,i) => {
inp.forEach(({label,value}) => {
op[label] = op[label] || {label}
op[label][alpha[i]] = value
})
return op
},{})
console.log(Object.values(op))
const r = ['a', 'b', 'c', 'l', 'p'];
const arr = [{
name: "ss3",
id: 'c'
}, {
name: "ss2",
id: 'b'
}, {
name: "ss4",
id: 'p'
}, {
name: "ss1",
id: 'a'
}]
var newArray =arr.map((i)=>{
let e = r[i];
if(i.id===e){
return i
}
})
console.log(newArray)
Expected output
const arr = [{
name: "ss1",
id: 'a'
}, {
name: "ss2",
id: 'b'
}, {
name: "ss3",
id: 'c'
}, {
name: "ss4",
id: 'p'
}
]
Given two arrays r and arr, I wish to sort arr with respect to r, i.e. in alphabetical order by id.
https://jsbin.com/yitijiboso/edit?html,js,output
I think this might be a concise (although not very performant) way to achieve the desired output:
const arr1 = ['a', 'b', 'c', 'l', 'p'];
const arr2 = [
{
name: "ss3",
id: 'c'
},
{
name: "ss2",
id: 'b'
}, {
name: "ss4",
id: 'p'
},
{
name: "ss1",
id: 'a'
}
];
arr2.sort((a, b) => arr1.indexOf(a.id) - arr1.indexOf(b.id));
console.log(arr2);
Easy:
make a map from main 'arr' keyBy 'id' https://www.npmjs.com/package/lodash.keyby
loop across 'r', if key exist in new map, get value and push to new array
const arrMap = _.keyBy(arr, 'id');
let newR = [];
r.forEach( key => {
if ( arrMap[key] ) {
newR.push( arrMap[key] );
}
} );
console.log( 'new array', newR );
Taking a clue from #Petr Broz, here's my suggestion:
const r = ['a', 'b', 'c', 'l', 'p'];
const arr = [
{
name: "ss3",
id: 'c'
},
{
name: "ss2",
id: 'b'
}, {
name: "ss4",
id: 'p'
},
{
name: "ss1",
id: 'a'
}
];
arr.sort((a, b) => r.indexOf(a.id) > r.indexOf(b.id));
console.log(arr);
Main difference is that this code utilizes the arrays as named by the OP and uses a greater than comparison operator. However, if you just want to have the array arr sorted in alphabetical order you don't need to compare it with array r:
const arr = [
{
name: "ss3",
id: 'c'
},
{
name: "ss2",
id: 'b'
}, {
name: "ss4",
id: 'p'
},
{
name: "ss1",
id: 'a'
}
];
arr.sort(function(a, b)
{
if (a.id > b.id) {
return 1;
}
else
if (a.id < b.id) {
return -1;
}
else
{
return 0;
}
});
console.log(arr);
Note, in this example the return values are numeric instead of boolean values which would be helpful if the array to be sorted were to have duplicate values.
I try to write insert into a tree data structure recursively in javascript with tree-node, but don't get it working.
So my question would be, how to approach the issue.
this is my data:
[ { id: 'a', children: [ 'b', 'c' ] },
{ id: 'b', children: [ '' ] },
{ id: 'c', children: [ 'b', 'd' ] },
{ id: 'd', children: [ 'b' ] } ]
I want that showing up in a tree like the following:
a
/\
b c
/\
b d
\
b
Edit: Added code
I Thought i could do something like this, but that doesn't work... and of course has high complexity because of the nested forEach:
var Node = require("tree-node");
var testarray =
[
{ id: 'a', children: [ 'b', 'c' ] },
{ id: 'b', children: [ '' ] },
{ id: 'c', children: [ 'b', 'd' ] },
{ id: 'd', children: [ 'b' ] }
]
function appendChildRecursive(parent) {
var childnode = new Node()
var data = parent.data("children")
testarray.forEach(function(item){
if(data !== undefined) {
data.forEach(function (child) {
if (item.id == child) {
childnode.data("id", child).data("children", item.children)
childnode = appendChildRecursive(childnode)
parent.appendChild(childnode)
}
})
}
})
return parent
}
var root = new Node();
root.data("id",testarray[0].id).data("children",testarray[0].children)
root=appendChildRecursive(root)
You could use a hash table for the last inserted nodes and keep the reference to the last nodes by overwriting the reference.
var data = [{ id: 'a', children: ['b', 'c'] }, { id: 'b', children: [] }, { id: 'c', children: ['b', 'd'] }, { id: 'd', children: ['b'] }],
tree = function (array) {
var nodes = Object.create(null),
r = {};
array.forEach(function (a) {
if (!nodes[a.id]) {
nodes[a.id] = { id: a.id, children: [] };
r = nodes[a.id];
}
a.children.forEach(function (b) {
nodes[b] = { id: b, children: [] };
nodes[a.id].children.push(nodes[b]);
});
});
return r;
}(data);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Your data structure is wrong.
Each 'leaf' should contain reference to the 'left' and 'right' element.
for example:
const first = { id: 'a', left: null, right: null };
const second = { id: 'b', left: null, right: first };
// etc...
The children approach would be more suitable for graph.
But you still have to store references, not ids.