Using array index variables instead of hard coded values - javascript

I have a following method, I want to use three variables declared in the 1st three lines instead of checking hard coded values using for loop and add it to res. I was trying following so that I only have to change the values inside successStates & failedStates
// if(successStates.find(x => x === filterVal)){
// filter1 = successStates[0];
// filter2 = successStates[1];
// }
getJobFilter() {
let successStates = ['ACCEPTED_STATE', 'ACTIVE_STATE'];
let failedStates = ['INACTIVE_STATE'];
let otherStates = ['UNKNOWN'];
let res = [];
let filter =
JSON.parse(sessionStorage.getItem('cdgFilter') || '{}');
for (let key in filter) {
if (key) {
if (key === 'collection_status') {
let filterVal: any;
let filter1, filter2;
if (filterVal === "SUCCESSFUL") {
filter1 = 'ACTIVE_STATE';
filter2 = 'ACCEPTED_STATE';
} else if (filterVal === "FAILED") {
filter1 = 'UNKNOWN_STATE';
filter2 = 'INACTIVE_STATE';
}
res.push({
'field': 'State',
'value': filter1
}, {
'field': 'State',
'value': filter2
});
} else {
res.push({
'field': key,
'value': filter[key].filter
});
}
}
}
return res;
}

The easiest way to do this is to use a map object:
const collectionStatusFilters = {
SUCCESSFUL: ['ACTIVE_STATE', 'ACCEPTED_STATE'],
FAILED: ['UNKNOWN_STATE', 'INACTIVE_STATE']
}
You can then replace your if statement thusly:
const filters = collectionStatusFilters[filterVal];
res = res.concat(
filters.map(filter => ({
field: 'State',
value: filter
}))
);

Related

Update array based on id Javascript

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);

Unable to parse this text to a JSON object

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)

Reformatting array of arrays to nested json in Javascript [duplicate]

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.

JavaScript - Filter object based on multiple values

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)
})

get value from nested object by key | refactoring 'for loop'

I have below method where i get value from the nested object , want to refactor it to best possible way but cannot use Object.hasOwnProperty because of linting rules
export const getValueFromNestedObject = (obj = {}, key = '') => {
let result;
for (let i = 0; i< Object.keys(obj).length; i++) {
if (typeof obj[Object.keys(obj)[i]] === 'object') {
result = getValueFromNestedObject(obj[Object.keys(obj)[i]], key);
if(typeof result != 'undefined') {
return result;
}
} else if (Object.keys(obj)[i] === key) {
return obj[key];
}
}
}
const valueObj = {
'#close' : {
'type': 'button',
'dom' : {
'data-linkName' : 'Close'
}
},
'#popupText': {
'type': 'HTML',
'options': {
'html': 'Pop Up Text that is required as result'
'label': 'Heads Up'
}
}
};
const key = 'html';
console.log(getValueFromNestedObject(valueObj, key));
expect(getValueFromNestedObject(valueObj, key)).toEqual('Pop Up Text that is required as result')

Categories

Resources