I am trying to convert a string into a delimited object key but I need some assistance on how to iterate over the length of the array and join accordingly.
SET('my.delimited.string.of.unknown.length')
const SET = key => (state, val) => {
if(key.indexOf('.') !== -1) {
let array = key.split(".")
for (var i = 0; i < array.length; i++) {
// what should I do here?
}
// desired output based on array length
// state[ array[0] ][ array[1] ] = val
// state.my.delimited.string.of.unknown.length = val
}
}
One of those very rare usecases for reduce:
const keys = key.split(".");
const prop = keys.pop();
keys.reduce((acc, key) => acc[key], state)[prop] = val;
For sure that could also be done with a for loop:
let array = key.split("."), acc = state;
for (var i = 0; i < array.length - 1; i++) {
acc = acc[ array[i] ];
}
acc[ array.pop() ] = val;
For setting a value, you could split the path and reduce the path by walking the given object. If no object exist, create a new property with the name. Later assign the value.
function setValue(object, path, value) {
var keys = path.split('.'),
last = keys.pop();
keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
}
var test = {};
setValue(test, "first.deep.property", 1);
setValue(test, "and.another.deep.property", 20);
console.log(test);
You could also do this with a single Array.reduce:
const makeObject = (arr, val, obj={}) => {
arr.split('.').reduce((r,c,i,a) => r[c] = i == a.length-1 ? val : {}, obj)
return obj
}
console.log(makeObject("first.deep.property", 1))
console.log(makeObject("and.another.deep.property", 20))
Related
I have a string in the form
Key=asdf, num=90, Key=ert, num=20, Key=yged, num=20, Key=kned, num=35
I have to filter only Key num pairs which has value 20 and store them into a Key Value pair such that Key=ert, num=20 will be first record and Key=yged, num=20 will be second record so on. How can I use Map in JavaScript so that always first value will go as key and second will go as value and form pairs in this case. I have used the following :
var dataString = JSON.parse(data).data;
var arrayVal = new Array();
arrayVal = dataString.split(', ');
for(a in arrayVal){
console.log(arrayVal[a]);
}
Array.map probably isn't the best tool for the job here. Array.reduce would be a better approach. Since you know what your delimiters are (namespaces and equal signs), you can logically split things up so that you know that every other iteration will give you a key/value. You can then create a mechanism to track what the last key is so you can map the value to it.
const str = 'Key=asdf, num=90, Key=ert, num=20, Key=yged, num=20, Key=kned, num=35';
const arr = str.split(', ').reduce( (acc, curr) => {
const entry = curr.split('=');
const key = entry[0];
const val = entry[1];
if (key === 'Key') {
acc['last_key'] = val
acc[val] = null;
} else if (key === 'num') {
acc[acc['last_key']] = val;
}
return acc;
}, {});
delete arr.last_key;
console.log(arr);
Here you go. It's kinda ugly.
let result = dataString.split(', ')
.map((value, index, array) =>
value === 'num=20' && array[index - 1])
.filter(x => x);
console.log(result);
Here's my say
const dataString = JSON.parse(data).data;
const arrayVal = dataString.split(', ');
const obj = {}; // initialize the object
for (let i = 0; i < arrayVal.length; i += 2) { // Iterating over two elements for the key and value
const key = arrayVal[i].split('=')[1];
const value = arrayVal[i + 1].split('=')[1];
obj[key] = value;
}
console.log(obj);
I'm trying to create an object from a string array.
I've this string array :
let BaseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
and I would like to have an object like that :
{
origin : ['develop', 'master'],
toto : ['branch'],
tata : ['hello', 'world']
}
So for the moment, I did this :
let Obj = {};
let RemoteObj = {};
for (let CurrentIndex = 0; CurrentIndex < BaseArray.length; CurrentIndex++) {
let Splits = BaseArray[CurrentIndex].split('/');
if (Splits[0] && Splits[1]) {
Obj[Splits[0]] = Splits[1].trim();
}
if (this.isObjectEmpty(RemoteObj)) {
RemoteObj = Obj;
} else {
RemoteObj = this.mergeObjects(RemoteObj, Obj);
}
console.log(RemoteObj);
}
And my utils functions are :
mergeObjects(...objs) {
let Result = {}, Obj;
for (let Ind = 0, IndLen = objs.length; Ind < IndLen; Ind++) {
Obj = objs[Ind];
for (let Prop in Obj) {
if (Obj.hasOwnProperty(Prop)) {
if (!Result.hasOwnProperty(Prop)) {
Result[Prop] = [];
}
Result[Prop].push(Obj[Prop]);
}
}
}
return Result;
}
isObjectEmpty(Obj) {
for (let Key in Obj) {
if (Obj.hasOwnProperty(Key)) {
return false;
}
return true;
}
}
I'm sure there is a better solution to do it but I can't do it.
So I'm open to any help !
Thanks by advance !
You can use Array.reduce() to create the object by splitting each string to the key and value, assigning an empty array to the key if it doesn't exist, and pushing the value to the array:
const BaseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
const result = BaseArray.reduce((r, str) => {
const [key, value] = str.split('/');
if(!r[key]) r[key] = [];
r[key].push(value);
return r;
}, {});
console.log(result);
You can use Array.reduce() for this approach. On each iteration of reduce you can split your string by / and use the first element as a key on the new object and then put the second element on the array associated with that key:
let BaseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
let res = BaseArray.reduce((acc, curr) =>
{
let [k, v] = curr.split("/");
(acc[k] = acc[k] || []).push(v);
return acc;
}, {});
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
You can use split and reduce
let BaseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
let op = BaseArray.reduce((op, inp) => {
let [key, value] = inp.split('/')
op[key] = op[key] || []
op[key].push(value)
return op
},{})
console.log(op)
You can use the reduce method to build your object.
let baseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
let baseobj = baseArray.reduce((acc, curr) => {
let items = curr.split('/');
let key = items[0];
let value = items[1];
if(acc[key] === undefined) {
acc[key] = [value]
} else {
acc[key] = [...acc[key], value];
}
return acc;
}, {});
console.log(baseobj);
You can use reduce & split the string which will give an array. Then use the element at index 0 of the array to create the object key. And push rest of the value to the array
let BaseArray = ['origin/develop', 'origin/kit/sub', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
let newArray = BaseArray.reduce(function(acc, curr) {
let splitCurr = curr.split('/');
if (!acc[splitCurr[0]]) {
acc[splitCurr[0]] = []
}
for (let i = 1; i < splitCurr.length; i++) {
acc[splitCurr[0]].push(splitCurr[i])
}
return acc;
}, {});
console.log(newArray)
im trying to remove adjacent duplicates but instead of desired result (3 results) i'm getting only 2 results
my Expected Output:
[{"mw://HOME_BIN":{"position":0}},{"mw://diagnosis_HOME":{"position":3}},{"mw://HOME_BIN":{"position":3}}]
here is what i have tried:
var arr = [{"mw://HOME_BIN":{"position":0}},{"mw://diagnosis_HOME":{"position":3}},{"mw://HOME_BIN":{"position":3}},{"mw://HOME_BIN":{"position":3}}];
var nArr = [];
for(var i = 0; i < arr.length;++i){
var key1 = Object.keys(arr[i]).join('');
var nLength = ((i + 1) > arr.length - 1 ) ? 0 : i + 1;
var key2 = Object.keys(arr[nLength]).join('');
if(key1 == key2) continue;
nArr.push(arr[i]);
}
console.log(nArr);
from the above result you can see one more element is missing
Easier to use filter:
var arr = [{"mw://HOME_BIN":{"position":0}},{"mw://diagnosis_HOME":{"position":3}},{"mw://HOME_BIN":{"position":3}},{"mw://HOME_BIN":{"position":3}}];
let lastKey;
const filtered = arr.filter((item) => {
const key = Object.keys(item)[0];
if (key === lastKey) return false;
lastKey = key;
return true;
});
console.log(filtered);
If you're looking for adjacent keys, you should just track the latest key, and not compare all of them.
var arr = [{"mw://HOME_BIN":{"position":0}},{"mw://diagnosis_HOME":{"position":3}},{"mw://HOME_BIN":{"position":3}},{"mw://HOME_BIN":{"position":3}}];
let result = [], prev_key = '', key;
for(let item of arr) {
key = Object.keys(item).sort().join();
if(key == prev_key) continue;
prev_key = key;
result.push(item);
}
console.log(result);
var arr =
[
{"mw://HOME_BIN":{"position":0}},
{"mw://diagnosis_HOME":{"position":3}},
{"mw://HOME_BIN":{"position":3}},
{"mw://HOME_BIN":{"position":3}}
];
var nArr = [];
arr.forEach((ar,index) => {
if(index === arr.length - 1) {
nArr.push(ar);
return;
}
if(JSON.stringify(ar) !== JSON.stringify(arr[index+1])){
nArr.push(ar);
}
})
console.log(nArr);
You can use JSON.stringify to compare whole objects instead of using single key, for your scalability
I have a array list which is bellow and want to assign a value from bottom to up.
Code sample:
var tempArrayList=[
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:null,org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:"Office",org3:null,org4:null,org5:"Pay"},
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:"head1",org2:null,org3:null,org4:"Payroll",org5:"Pay"}
];
for(var i=0;i<tempArrayList.length;i++) {
var temp=tempArrayList[i];
var org1=temp.org1;
var org2=temp.org2;
var org3=temp.org3;
var org4=temp.org4;
var org5=temp.org5;
document.write(JSON.stringify(temp));
document.writeln("<br>");
}
My Questions: how can I set the org2 value to org1, org3 value to org2......
// if org1 is null then temp.org1 = temp.org2, temp.org2 = temp.org3, temp.org3 = temp.org4, temp.org4 = temp.org5
// if org1 and org2 is null then temp.org1 = temp.org3, temp.org2 = temp.org4, temp.org3 = temp.org5, temp.org4 = null
Filter all the null out of values array then loop over keys and assign filtered value or null
var tempArrayList=[
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:null,org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:"Office",org3:null,org4:null,org5:"Pay"},
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:"head1",org2:null,org3:null,org4:"Payroll",org5:"Pay"}
];
tempArrayList.forEach((o) => {
const vals = Object.values(o).filter(v => v);
Object.keys(o).forEach((key, i) => o[key] = vals[i] || null);
});
console.log(tempArrayList)
.as-console-wrapper {max-height:100%!important;}
Accepted answer fails on falsy values ({org1:false}), mutates original object and falsely assumes Object.keys returns in a particular order.
There is no guarantee in the order Object.keys returns the array of keys in the right order:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
in the same order as that provided by a for...in loop
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
A for...in loop iterates over the properties of an object in an arbitrary order
If the code with Object.keys works then try it again but add this first:
tempArrayList = tempArrayList.map(
x =>
Object.keys(x).reverse().reduce(
(acc,key) => {acc[key]=x[key];return acc;}
,{}
)
);
Here is one solution to the problem that doesn't rely on Object.keys order, does not mutate and does not fail on falsy member values:
const collapse = function(direction,reason,subject,seed,keys){
if(Array.isArray(subject)){
keys = (function(x){
const ret = [];
while(++x<subject.length){
ret.push(x);
}
return ret;
}(-1));
}
keys =
(direction>0)
? keys
: keys.reverse();
const sortedKeys = keys.filter(
function(key){return !reason(subject[key])}
).concat(
keys.filter(
function(key){return reason(subject[key])}
)
);
return keys.reduce(
function(acc,key,index) {
acc[key] = subject[sortedKeys[index]]
return acc;
}
,seed
);
}
const collapseLeft = function(reason,keys){
return function(seed,subject){
return collapse(1,reason,subject,seed,keys);
}
};
const collapseRight = function(reason,keys){
return function(seed,subject){
return collapse(-1,reason,subject,seed,keys);
}
};
const tempArrayList=[
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:null,org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:"Office",org3:null,org4:null,org5:"Pay"},
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:"head1",org2:null,org3:"Pay",org4:null,org5:null}
];
const isNull = function(x){return x===null;};
console.log(
tempArrayList.map(
function(item){
//seed can be an object ({}) or array ([]) see other log
return collapseLeft(
isNull,
["org1", "org2", "org3", "org4", "org5"]
)
({},item);
}
)
);
//collapse right example
console.log(
JSON.stringify(
collapseRight(
isNull,
["org1", "org2", "org3", "org4", "org5"]
)({},{org1:"head1",org2:null,org3:"Pay",org4:null,org5:null})
,undefined
,2
)
);
//array example (seed is [])
console.log(
JSON.stringify(
collapseRight(isNull)([],[1,2,3,null,4,null,5])
,undefined
,2
)
);
Is this what you're looking for?
This code loops through the object keys, moving the values up and setting the last one to null.
var tempArrayList=[
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:null,org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:null,org2:"Office",org3:null,org4:null,org5:"Pay"},
{org1:null,org2:"Office",org3:"HR",org4:"Payroll",org5:"Pay"},
{org1:"head1",org2:null,org3:null,org4:"Payroll",org5:"Pay"}
];
for (var i = 0; i < tempArrayList.length; i++) {
var keys = Object.keys (tempArrayList[i]);
for (var j = 0; j < keys.length; j++) {
if (j < keys.length - 1) {
tempArrayList[i][keys[j]] = tempArrayList[i][keys[j + 1]];
} else {
tempArrayList[i][keys[j]] = null;
}
}
}
I was able to pull all single integers after 'reduce', but not working when there's all duplicates and output should be 0, not hitting my else or else if - code keeps outputting 0 vs the single integers
var singleNumber = function(nums) {
var sorted_array = nums.sort();
for (var i=0; i < sorted_array.length; i++){
var previous = sorted_array[i-1];
var next = sorted_array[i+1];
var singles = {key: 0};
var singlesArray = [];
if (sorted_array[i] !== previous && sorted_array[i] !== next){
singlesArray.push(sorted_array[i]);
singlesArray.reduce(function(singles, key){
singles.key = key;
//console.log('key', key);
return singles.key;
},{});
}
else if(singlesArray.length === 0) {
singles.key = 0;
return singles.key;
}
}
console.log('singles.key', singles.key);
return singles.key;
};
console.log(singleNumber([2,1,3,4,4]));
// tests
const n1 = [1,2,3,4,4] //[1,2,3]
const n2 = [1] //[1]
const n3 = [1,1] //0
const n4 = [1,1,1] //0
const n5 = [1,5,3,4,5] //[1,3,4]
const n6 = [1,2,3,4,5] //[1,2,3,4,5]
const n7 = [1,5,3,4,5,6,7,5] //[1,3,4,6,7]
const singleNumber = numbers => {
const reducer = (acc, val) => {
// check to see if we have this key
if (acc[val]) {
// yes, so we increment its value by one
acc[val] = acc[val] + 1
} else {
// no, so it's a new key and we assign 1 as default value
acc[val] = 1
}
// return the accumulator
return acc
}
// run the reducer to group the array into objects to track the count of array elements
const grouped = numbers.reduce(reducer, {})
const set = Object.keys(grouped)
// return only those keys where the value is 1, if it's not 1, we know its a duplicate
.filter(key => {
if (grouped[key] == 1) {
return true
}
})
// object.keys makes our keys strings, so we need run parseInt to convert the string back to integer
.map(key => parseInt(key))
// check to array length. If greater than zero, return the set. If it is zero, then all the values were duplicates
if (set.length == 0) {
return 0
} else {
// we return the set
return set
}
}
console.log(singleNumber(n7))
https://jsbin.com/sajibij/edit?js,console