I want to update he array based on id with some conditions. Conditions were =
const data1 = [
{ type:"foo", id:"123"},
{ type:"bar", id:"124"},
]
const update1 = {type:"bar",id:"123"}
const update2 = {type:"foo", id:"125"}
const update3 = {type:"bar", id:"123"}
console.log(myupdate(data1, update1))
should update the data1 as bellow based on id
here the type is changed to bar
data1 = [ { type:"bar", id:"123"},
{ type:"bar", id:"124"}, ]
console.log(myupdate(data1, update2))
here as no item with id 125 exist so it adds a new one
data1 = [ { type:"bar", id:"123"},
{ type:"bar", id:"124"},
{ type:"foo", id:"125"} ]
console.log(myupdate(data1, update3))
here type is not changed so it should return the array as it is.
data1 = [{ type:"bar", id:"123"},
{ type:"bar", id:"124"},
{ type:"foo", id:"125"}
]
I have tried this code but it doesn't work
const myupdate = (arr, element) => {
arr.map((item)=>{
console.log(item, "ele",element)
if(item.id != element.id){
arr.push(element)
return
}
if(item.id === element.id && item.type === element.type){
return
}
if(item.id === element.id && item.type != element.type){
arr.filter(item => item !== element).push(element)
return
}
})
}
You need to look through the array and find the correct item. If there is no item with the specified requirement, you'll add a new one. Here is an example:
const data = [
{ type: "foo", id: "123"},
{ type: "bar", id: "124"},
]
const update = (data, value) => {
console.log('Updating/Inserting', value);
const existingItem = data.find(item => item.id === value.id);
if (existingItem === undefined) {
data.push(value);
} else {
existingItem.type = value.type;
}
}
console.log('before', data);
update(data, {type:"bar",id:"123"});
console.log(data);
update(data, {type:"foo", id:"125"});
console.log(data);
update(data, {type:"bar", id:"123"});
console.log(data);
I have the following structure of info, that I need to convert into a JSON with properties and data. Originally its plain text, but I have converted it into an array to make it easier
[ '# Server',
'redis_version:5.0.5',
'redis_git_sha1:00000000',
'redis_git_dirty:0',
'redis_build_id:7983a619928f1f2d',
'redis_mode:standalone',
'os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64',
'arch_bits:64',
'multiplexing_api:epoll',
'atomicvar_api:atomic-builtin',
'gcc_version:6.3.0',
'process_id:1',
'run_id:1348856f2bcc8af5cfef205f1880fedb68602201',
'tcp_port:6379',
'uptime_in_seconds:10484766',
'uptime_in_days:121',
'hz:10',
'configured_hz:10',
'lru_clock:11364638',
'executable:/data/redis-server',
'config_file:/etc/redis.conf',
'',
'# Clients',
'connected_clients:34',
'client_recent_max_input_buffer:2',
'client_recent_max_output_buffer:0',
'blocked_clients:0',
'',
'# Memory',
'used_memory:1568376',
'used_memory_human:1.50M',
'used_memory_rss:2768896',
'used_memory_rss_human:2.64M',
'used_memory_peak:5866848',
'used_memory_peak_human:5.60M',
'used_memory_peak_perc:26.73%',
'used_memory_overhead:1406080',
'used_memory_startup:791240',
'used_memory_dataset:162296',
'used_memory_dataset_perc:20.88%',
'allocator_allocated:1571256',
'allocator_active:2084864',
'allocator_resident:5722112',
'total_system_memory:33730531328',
'total_system_memory_human:31.41G',
'used_memory_lua:37888',
'used_memory_lua_human:37.00K' ]
And im trying to parse it into something that looks like the below structure
{
Server : {
redis_version : "5.0.5",
redis_git_sha1: "00000000"
...
},
Clients: {
connected_clientes: 54,
client_recent_max_input_buffer: 2,
...
}
Memory: {
used_memory: 1568376,
used_memory_human: "1.50M"
...
}
}
So far I have been able to create the subobjects
{ Server: {},
Clients: {},
Memory: {},
Persistence: {},
Stats: {},
Replication: {},
CPU: {},
Cluster: {},
Keyspace: {} }
Using this code where i managed to create the objects:
var obj = {};
console.log(lines)
for (let i in lines) {
if (lines[i].includes("#")) {
let prop = lines[i].toString()
let propFormat = prop.substring(2)
obj[propFormat] = {}
} else if (!lines[i].includes("#") && lines[i] != "") {
// console.log(lines[i])
}
}
But im stuck after that, can someone bring some light on how to continue?
I would use a forEach to loop through the array.
Then using .substring to check if it's a new 'key'; remember that key so you can add all the values, until the next key is found;
const data = [ '# Server', 'redis_version:5.0.5', 'redis_git_sha1:00000000', 'redis_git_dirty:0', 'redis_build_id:7983a619928f1f2d', 'redis_mode:standalone', 'os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64', 'arch_bits:64', 'multiplexing_api:epoll', 'atomicvar_api:atomic-builtin', 'gcc_version:6.3.0', 'process_id:1', 'run_id:1348856f2bcc8af5cfef205f1880fedb68602201', 'tcp_port:6379', 'uptime_in_seconds:10484766', 'uptime_in_days:121', 'hz:10', 'configured_hz:10', 'lru_clock:11364638', 'executable:/data/redis-server', 'config_file:/etc/redis.conf', '', '# Clients', 'connected_clients:34', 'client_recent_max_input_buffer:2', 'client_recent_max_output_buffer:0', 'blocked_clients:0', '', '# Memory', 'used_memory:1568376', 'used_memory_human:1.50M', 'used_memory_rss:2768896', 'used_memory_rss_human:2.64M', 'used_memory_peak:5866848', 'used_memory_peak_human:5.60M', 'used_memory_peak_perc:26.73%', 'used_memory_overhead:1406080', 'used_memory_startup:791240', 'used_memory_dataset:162296', 'used_memory_dataset_perc:20.88%', 'allocator_allocated:1571256', 'allocator_active:2084864', 'allocator_resident:5722112', 'total_system_memory:33730531328', 'total_system_memory_human:31.41G', 'used_memory_lua:37888', 'used_memory_lua_human:37.00K' ];
// Result
let res = {};
// Remember latest prop
let latestProp = null;
// For each data entry
data.forEach((d) => {
// Starting with #: new key
const firstChar = d.substring(0, 1);
if (firstChar === '#') {
latestProp = d.substring(2);
res[latestProp] = {};
} else {
// Add key-value
let s = d.split(':');
if (s.length > 1) {
res[latestProp][s[0]] = s[1];
}
}
});
console.log(res);
My suggestion would be something like this:
//Declaring prop before the loop so that it isn't reset each iteration
let prop;
for(...) {
...
} else if (!lines[i].includes("#") && lines[i] != "") {
let split = lines[i].split(":");
let key = split[0];
let value = split[1];
obj[prop][key] = value
}
here is a working snippet using array.reduce , I also removed the "" values from the array
const tobeConverted= [ '# Server',
'redis_version:5.0.5',
'redis_git_sha1:00000000',
'redis_git_dirty:0',
'redis_build_id:7983a619928f1f2d',
'redis_mode:standalone',
'os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64',
'arch_bits:64',
'multiplexing_api:epoll',
'atomicvar_api:atomic-builtin',
'gcc_version:6.3.0',
'process_id:1',
'run_id:1348856f2bcc8af5cfef205f1880fedb68602201',
'tcp_port:6379',
'uptime_in_seconds:10484766',
'uptime_in_days:121',
'hz:10',
'configured_hz:10',
'lru_clock:11364638',
'executable:/data/redis-server',
'config_file:/etc/redis.conf',
'# Clients',
'connected_clients:34',
'client_recent_max_input_buffer:2',
'client_recent_max_output_buffer:0',
'blocked_clients:0',
'# Memory',
'used_memory:1568376',
'used_memory_human:1.50M',
'used_memory_rss:2768896',
'used_memory_rss_human:2.64M',
'used_memory_peak:5866848',
'used_memory_peak_human:5.60M',
'used_memory_peak_perc:26.73%',
'used_memory_overhead:1406080',
'used_memory_startup:791240',
'used_memory_dataset:162296',
'used_memory_dataset_perc:20.88%',
'allocator_allocated:1571256',
'allocator_active:2084864',
'allocator_resident:5722112',
'total_system_memory:33730531328',
'total_system_memory_human:31.41G',
'used_memory_lua:37888',
'used_memory_lua_human:37.00K' ]
let index = 0;
let keys=[]
const reducedObj=tobeConverted.reduce((a,c)=>{
if(c.includes("#")){
const key= c.split("#")[1].trim()
keys.push(key)
index++;
return {...a,[key]:{}}
}else{
const split =c.split(":")
console.log(split)
const subkey =split[0].trim()
const subValue =split[1].trim()
a[keys[index-1]][subkey] = subValue;
}
return a
},{})
I think you can do something like this:
function parse (lines) {
const result = {};
let section;
lines.forEach((line) => {
if (line) {
if (line.startsWith('# ')) {
section = line.substring(2);
result[section] = {};
} else {
const [prop, value] = line.split(':');
result[section][prop] = value;
}
}
});
return result;
}
const textdata = [ '# Server', 'redis_version:5.0.5', 'redis_git_sha1:00000000', 'redis_git_dirty:0', 'redis_build_id:7983a619928f1f2d', 'redis_mode:standalone', 'os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64', 'arch_bits:64', 'multiplexing_api:epoll', 'atomicvar_api:atomic-builtin', 'gcc_version:6.3.0', 'process_id:1', 'run_id:1348856f2bcc8af5cfef205f1880fedb68602201', 'tcp_port:6379', 'uptime_in_seconds:10484766', 'uptime_in_days:121', 'hz:10', 'configured_hz:10', 'lru_clock:11364638', 'executable:/data/redis-server', 'config_file:/etc/redis.conf', '', '# Clients', 'connected_clients:34', 'client_recent_max_input_buffer:2', 'client_recent_max_output_buffer:0', 'blocked_clients:0', '', '# Memory', 'used_memory:1568376', 'used_memory_human:1.50M', 'used_memory_rss:2768896', 'used_memory_rss_human:2.64M', 'used_memory_peak:5866848', 'used_memory_peak_human:5.60M', 'used_memory_peak_perc:26.73%', 'used_memory_overhead:1406080', 'used_memory_startup:791240', 'used_memory_dataset:162296', 'used_memory_dataset_perc:20.88%', 'allocator_allocated:1571256', 'allocator_active:2084864', 'allocator_resident:5722112', 'total_system_memory:33730531328', 'total_system_memory_human:31.41G', 'used_memory_lua:37888', 'used_memory_lua_human:37.00K' ];
const parsedObj = {};
for (data of textdata) {
// checking for keys
if (data.startsWith("#")) {
parsedObj[data.split(" ")[1]] = {};
continue;
}
if (Object.keys(parsedObj).length && data) {
let lastKeyFound = Object.keys(parsedObj).pop();
const [key, value] = data.split(':');
parsedObj[lastKeyFound][key] = value
}
}
// console.log(parsedObj)
// converting parsedObj to json
const textdataJson = JSON.stringify(parsedObj, null, 2)
console.log(textdataJson)
I have an array like
[
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1",
.
.
.
]
Wherein my first string before | is the parent and the second string before | is the child and the third string after the second | is the subchild
How can I convert this array into an object like
[
{
"id": "parent1",
"children":[
{
"id": "child1",
"children":[
{
"id": "subChild1"
}
]
}
]
}
]
Parent -> child -> subchild object
Based on Sebastian's answer I tried below using typescript
private genTree(row) {
let self = this;
if (!row) {
return;
}
const [parent, ...children] = row.split('|');
if (!children || children.length === 0) {
return [{
id: parent,
children: []
}];
}
return [{
id: parent,
children: self.genTree(children.join('|'))
}];
}
private mergeDeep(children) {
let self = this;
const res = children.reduce((result, curr) => {
const entry = curr;
const existing = result.find((e) => e.id === entry.id);
if (existing) {
existing.children = [].concat(existing.children, entry.children);
} else {
result.push(entry);
}
return result;
}, []);
for (let i = 0; i < res.length; i++) {
const entry = res[i];
if (entry.children && entry.children.length > 0) {
entry.children = self.mergeDeep(entry.children);
}
};
return res;
}
private constructTree(statKeyNames){
let self = this;
const res = this.mergeDeep(statKeyNames.map(self.genTree).map(([e]) => e));
console.log(res);
}
but this gives me:
Cannot read property 'genTree' of undefined" error
Update:
As per Sebastian's comment changed self.genTree to this.genTree.bind(this) and it worked without any issues
You could use a mapper object which maps each object to it's unique path (You could map the object with each id, but id is not unique here). Then reduce each partial item in the array. Set the root object as the initialValue. The accumulator will be the parent object for the current item. Return the current object in each iteration.
const input = [
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent1|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1"
],
mapper = {},
root = { children: [] }
for (const str of input) {
let splits = str.split('|'),
path = '';
splits.reduce((parent, id, i) => {
path += `${id}|`;
if (!mapper[path]) {
const o = { id };
mapper[path] = o; // set the new object with unique path
parent.children = parent.children || [];
parent.children.push(o)
}
return mapper[path];
}, root)
}
console.log(root.children)
You have to use recursion for that. Take a look here:
const arr = [
"parent1|child1|subChild1",
"parent1|child1|subChild2",
"parent|child2|subChild1",
"parent1|child2|subChild2",
"parent2|child1|subChild1",
"parent2|child1|subChild2",
"parent2|child2|subChild1"
];
function genTree(row) {
const [parent, ...children] = row.split('|');
if (!children || children.length === 0) {
return [{
id: parent,
children: []
}];
}
return [{
id: parent,
children: genTree(children.join('|'))
}];
};
function mergeDeep(children) {
const res = children.reduce((result, curr) => {
const entry = curr;
const existing = result.find((e) => e.id === entry.id);
if (existing) {
existing.children = [].concat(existing.children, entry.children);
} else {
result.push(entry);
}
return result;
}, []);
for (let i = 0; i < res.length; i++) {
const entry = res[i];
if (entry.children && entry.children.length > 0) {
entry.children = mergeDeep(entry.children);
}
};
return res;
}
const res = mergeDeep(arr.map(genTree).map(([e]) => e));
console.log(JSON.stringify(res, false, 2));
I used two helpers here: genTree(row) which recursively generates a simple tree from each row, and mergeDeep(children) which reduces the first-level trees in the result of arr.map(genTree).map(([e]) => e), and then iterates over the array and recursively does the same thing to all children of each entry.
I need to filter some data based on multiple values. Language, title and slug
[
{
de: "4567uy55",
en: "654321",
lang: [
{
id: "654321",
language: "English",
title: "Title1"
},
{
id: "4567uy55",
language: "German",
title: "Title2"
}
],
slug: 'some-slug'
},
...
]
What I have now returns all objects which have one or part of the filters(in case title is This is a title, the word this should match), but I need to return objects which have all of them.
I used an object flattner just to get all properties and values in one object, but I can't get it to filter the way I need it.
multiFilter = (arr, filters) => {
console.log(filters)
console.log(arr)
let newArray = []
for (let c of arr) {
let flatCourse = flatten(c)
for (let k in flatCourse) {
const keyArr = k.split('/')
const filterKeys = Object.keys(filters)
Object.keys(filters).map((key) => {
if (keyArr.includes(key)) {
const flatVal = flatCourse[k].toString().toLowerCase()
const filterVal = filters[key].toString().toLowerCase()
console.log(flatVal)
console.log(filterVal)
if (flatVal.includes(filterVal)) {
arr = []
arr.push(c)
newArray.push(c)
}
}
})
}
}
return newArray
}
Filters look like this:
[
language:["English"],
title: ["Some title"],
slug:["some slug"]
]
Instead of mixing for loops and functional chaining you could just go with one of them:
multiFilter = (arr, filters) =>
arr.map(flatten).filter(el => // filter out elements from arr
Object.entries(filters).every(([fKey, fValues]) => // ensure that every key is included in the object
Object.entries(el).some(([oKey, oValue]) =>
oKey.split("/").includes(fKey) && fValues.includes(oValue)// make sure that at least one of the values equals the elements value
)
)
);
arr.filter(course => {
// Returns an array of booleans corresponding to whether or not each filter condition is satisfied
return Object.keys(filters).map(key => {
return filters[key].map(filter => {
// Special case here because lang is an array
if (key == 'language' && course.lang != undefined) {
return course.lang.some(lang => lang[key].includes(filter))
}
if (course[key] == undefined) {
return false
}
return course[key].includes(filter)
}).every(result => result == true)
}).every(result => result == true)
})