How to iterate over object - javascript

I have an object like this:
const params = {
'userId[]': [1, 2],
'empId': 2,
advance: 'hello',
};
and I want to make a string like this:
userId[]=1&userId[]=2&empId=2&advance=hello
I am trying like this:
const myResult = Object.entries(params)
.map(([key, value]) => {
if (Array.isArray(value)) {
let result;
value.forEach(item => {
`${key}=${value}`
})
return result
}
// return
})
.join('&');
console.log(myResult);
but not able to figure out what to do next.

With a few changes, adding concatenation and non-array values:
const params = {
"userId[]": [1, 2],
empId: 2,
advance: "hello",
}
const myResult = Object.entries(params)
.map(([key, value]) => {
// Assume non-array result as default
let result = `${key}=${value}`
if (Array.isArray(value)) {
// Override for arrays
const r = value
.map((item) => {
return `${key}=${item}`
})
.join("&")
result = r
}
return result
})
.join("&")
console.log(myResult)

URLSearchParams can do most of the work for us, but we still have to handle the array ourselves:
const params = {
'userId[]': [1, 2],
'empId': 2,
advance: 'hello',
};
const p = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (Array.isArray(value)) {
for (const item of value) {
p.append(key, item);
}
} else p.append(key, value);
}
console.log(p.toString());
Looping through the entries of our object, we check if the value is an array. If it isn't we append it, otherwise, we append all its items. URLSearchParams makes the string for us; all we do is tell it what to use for the string :)
Note: "%5b%5D" is the same as "[]" but it's URI encoded. It should be treated the same by the server.

You can do the following instead of iterating over the object:
url = Object.keys(params).map(function(k) {return k + '=' + params[k]}).join('&')"
which would give you
'userId[]=1,2&empId=2&advance=hello'
I think you need this(guessing that you made a typo error)

Related

need to convert object to JSON value

I have following request body,
{
name1:"john,doe",
name2:"peter,frank"
}
I need to get output as following
{
"name1":["john","doe"],
"name2":["peter","frank"],
}
I am trying to use array methods.
Iterate over the object with for...in, and split the value into an array. Then JSON.stringify the object.
const res = {
name1:"john,doe",
name2:"peter,frank"
};
for (const key in res) {
res[key] = res[key].split(',');
}
console.log(JSON.stringify(res));
You can use Object.entries() and iterate over every key value and convert value into array and get back the new object using Object.fromEntries().
const o = { name1: "john,doe", name2: "peter,frank" },
result = Object.fromEntries(Object
.entries(o)
.map(([key, val]) => ([key, val.split(',')]))
);
console.log(result);

How can I extract from an array of arrays all the arrays that have the same value in their first field?

The following function elegantly finds duplicates in 1-dimensional arrays:
const findDuplicates = (dataArray) => {
const duplicates = dataArray.filter((e, index, arr) => arr.indexOf(e) !== index);
return (duplicates);
};
When I send it (for example) this array
['123456', '787877', '763223', '787877', '854544'] it returns ['787877'].
What I need is something similar that works for a 2-d array so (for instance) inputting
[
['123456', 'Smith'],
['787877', 'Jones'],
['763223', 'Waldo'],
['787877', 'Quagmire'],
['854544', 'Miller']
]
returns
[['787877', 'Jones'], ['787877', 'Quagmire']]
(To be clear, I'm only interested in whether the 1st field of each sub-array is a dupe.)
const findDuplicates = (dataArray) => {
const duplicates = dataArray.filter((e, index, arr) => {
return arr.some((val, i) => (index !== i && val[0] === e[0]))
})
return (duplicates);
};
const result = findDuplicates([
['123456', 'Smith'],
['787877', 'Jones'],
['763223', 'Waldo'],
['787877', 'Quagmire'],
['854544', 'Miller']
])
console.log(result)
You could take an object and use a boolean values to indicae duplicates. Then filter the array.
const
findDuplicates = data => {
const
keys = data.reduce((r, [v]) => {
r[v] = r[v] !== undefined;
return r;
}, {});
return data.filter(([v]) => keys[v]);
},
data = [['123456', 'Smith'], ['787877', 'Jones'], ['763223', 'Waldo'], ['787877', 'Quagmire'], ['854544', 'Miller']],
result = findDuplicates(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Invert key value in js object

I can't figure out how I can change :
{"first":["de"], "second":["ab","de"], "third":["de"]}
to:
{"de":["first", "second", "third"], "ab":["second"]}
I want to associate unique values with list of containing keys. What I tried(but I think I'm far from it):
const data = {
"first":["de"],
"second":["ab","de"],
"third":["de"]
}
console.log(
Object
.keys(data).reduce(function(obj, key) {
obj[data[key]] = key;
return obj;
}, {})
)
Thanks for your help!
Object.entries to get it into an array, reduce to build the new object, and forEach to loop over the array
const o = {"first":["de"], "second":["ab","de"], "third":["de"]}
const result = Object.entries(o).reduce((obj, [key, arr])=>{
arr.forEach(lng => {
obj[lng] = obj[lng] || [];
obj[lng].push(key);
})
return obj
}, {});
console.log(result);
You have to loop the array and for each item in the array check if an array for that value exists in the accumulator or not before adding it:
let result = Object.entries(data).reduce((acc, [key, arr]) => { // for each key-array of the original object
arr.forEach(value => { // for each value in the array
acc[value] = acc[value] || []; // create an array in the output object if it doesn't already exist
acc[value].push(key); // push the key to it
});
return acc;
}, {});
I also used Object.entries with each entry desctuctured as [key, arr] so I don't have to use the extra [key] to get the array while using Object.keys.
Demo:
let data = {"first":["de"], "second":["ab","de"], "third":["de"]};
let result = Object.entries(data).reduce((acc, [key, arr]) => {
arr.forEach(value => {
acc[value] = acc[value] || [];
acc[value].push(key);
});
return acc;
}, {});
console.log(result);
On reduce callback, data[key] is an array of string values. So it is needed to loop that data[key] array values and assign value for each array item.
const data = {
"first":["de"],
"second":["ab","de"],
"third":["de"]
}
console.log(
Object.keys(data).reduce(function(obj, key) {
data[key].forEach((val) => {
obj[val] ? obj[val].push(key) : obj[val] = [ key ];
});
return obj;
}, {})
)
Try this (naive solution), if this works for you
const data = { first: ["de"], second: ["ab", "de"], third: ["de"] };
let dataMap = new Map();
Object.keys(data).forEach((key) => {
data[key].forEach((val) => {
if (dataMap.has(val)) {
dataMap.set(val, [...dataMap.get(val), key]);
} else {
dataMap.set(val, [key]);
}
});
});
let nData = [];
dataMap.forEach((value, key) => {
nData.push({
[key]: value
});
});
console.log(nData);
You could take a double reduce with the entries.
const
data = { first: ["de"], second: ["ab", "de"], third: ["de"] },
result = Object
.entries(data)
.reduce((o, [value, keys]) => keys.reduce((q, key) => {
(q[key] ??= []).push(value);
return q;
}, o), {});
console.log(result);
I'm not using reduce but here's a "bruteforce" for your problem which works:
res = {};
Object.keys(data).forEach(key => {
data[key].forEach(el => {
if (! res[el])
res[el] = [];
if (! res[el].includes(key))
res[el].push(key);
})
});

How to process an array one by one in javascript?

I have an array of values in a stream and you wish to pipe it such that it will emit the arrays values individually, one by one and wait for them all to be completed before processing another array
// This is the array:
let arr = [[1,2,3], [4,5,6]];
let data = arr.filter( (value) => {
let newdata = value.filter((newVal, index) => {
if (newVal !== value[index]) {
return '' ;
}
});
});
console.log(data);
// Output: []
// Expected output: [[], []]
arr.map(x => x.map((y, index) => {if(y !== y[index]){return ''}}))
This will return [["", "", ""], ["", "", ""]]
For [[], []] filter out those blank strings:
arr.map(x => x.map((y, index) => {if(y !== y[index]){return ''}}).filter(z => z !== ""))
At root use Map instead of filter:
let arr = [[1,2,3], [4,5,6]];
let data = arr.map( (value) => {
let newdata = value.filter((newVal, index) => {
if (newVal !== value[index]) {
return '' ;
}
});
return newdata;
});
console.log(data);

Reversing an Object.entries conversion

I am using Object.entries in order to get some values out of a nested object and filter it.
obj = Object.entries(obj)
.filter(([k, v]) => {
return true; // some irrelevant conditions here
});
My object ends up as an array of arrays, of keys and vals.
[['key1', val]['key2', val]['key3', val]]
Is there a straightforward way to map these back into an object? The original object structure is:
{ key:val, key2:val2, key3:val3 }
Sure, just use .reduce to assign to a new object:
const input = { key:'val', key2:'val2', key3:'val3' };
const output = Object.entries(input)
.filter(([k, v]) => {
return true; // some irrelevant conditions here
})
.reduce((accum, [k, v]) => {
accum[k] = v;
return accum;
}, {});
console.log(output);
In modern browsers, you can also use Object.fromEntries which makes this even easier - you can just pass an array of entries, and it'll create the object from those entries.
const input = { key:'val', key2:'val2', key3:'val3' };
const output = Object.fromEntries(
Object.entries(input)
.filter(([k, v]) => {
return true; // some irrelevant conditions here
})
);
console.log(output);
For new browsers, use Object.fromEntries:
Object.fromEntries(arr);
For older js, it can still be a one liner.
arr.reduce((acc,[k,v])=>(acc[k]=v,acc),{})
Example:
Object.entries(sampleObject) // Turn object to array
.reduce((acc,[k,v])=>(acc[k]=v,acc),{}) // Turn it back to object.
Using Object.assign with a map that maps [k,v] => {[k]: v}
For example, the code below will only keep keys beginning with key
var obj = {
key: 1,
key2: 2,
key3: 3,
removed: 4,
alsoRemoved: 5
}
obj = Object.assign({}, ...Object.entries(obj)
.filter(([k, v]) => {
return k.startsWith('key');
})
.map(([k, v]) => ({[k]: v}))
);
console.log(obj);
Using reduce with deconstruction and comma operator:
const input = { key:'val', key2:'val2', key3:'val3' };
const output = Object.entries(input)
.filter(([k, v]) => {
return true; // some irrelevant conditions here
})
.reduce((acc, [k, v]) => (acc[k] = v, acc), {});
which should give the same functionality as CertainPerformance's answer with a bit more concise syntax
let entries = Object.entries({e: 'e', q: 'q'});
let reverse = entries.map(([t, r]) => ({[t]: r})).reduce((pv, cv) =>{return Object.assign(pv, cv)});
console.log(reverse);
If you know exactly which entries you want to exclude, you can use object deconstruction combined with spreading:
function clean(obj) {
const { unwanted1, unwanted2, ...wanted } = obj;
return { ...wanted };
}
For some cases, this might be the cleanest solution.
function undoEntries(entered){
let output = {};
entered.forEach(item => {
output[item[0]] = item[1]
});
return output;
};
// Example
const obj = { a: 1, b: 2, c: 3};
const input = Object.entries(obj);
const output = undoEntries(input);
console.log(output);

Categories