Javascript - find in object based on key and extract the found data - javascript

I have a localstorage object, and I need to find all data and extract it based on the key.
Example of object:
Storage {
agency-list|radio-radio2: "true",
agency|radio-radio1: "true", length: 2
.....}
This is how I get the param for searching:
let formID = $('form').attr('id');
let regex = new RegExp("^" + formID + "|");
For example, I would like to extract all key value, where the key is beginning with agency|, in separate array or object.
What is the best approach for this problem?

You can use Object.keys() method to iterate over your keys
let Storage = {
"agency-list|radio-radio2": "true",
"agency|radio-radio1": "true",
length: 2 }
let otherStorage = [];
Object.keys(Storage).forEach(key=>{
if(key.startsWith("agency|")){
otherStorage.push(key);
}
});
console.log(otherStorage);

A combination Object.keys() and filter can help you :
let formID = $('form').attr('id');
let regex = new RegExp(`^${formID}|`);
const Storage = {
"agency-list|radio-radio2": "true",
"agency|radio-radio1": "true",
length: 2
};
const agencies = Object.keys(Storage).filter( key => regex.test(key));

Simply loop through all your object's properties, test if the prop matches the regex, and add it to result if it does.
let result = {};
for(let prop in storage){
if(prop.match(regex)){
result[prop] = storage[prop];
}
}

Turn your storage into an array with Object.entries
Filter the entries with Array#filter and check the regex with test.
Put everything back together into an object with Array#reduce
I also used destructuring parameters [key, value], since Object.entries outputs everything as an array of [key, value] arrays.
let formID = $('form').attr('id');
let regex = new RegExp("^" + formID + "|");
Object.entries(localStorage)
.filter(([key, value]) => regex.test(key))
.reduce((obj, [key, value]) => (obj[key] = value, obj), {});

Related

Convert string array into object with same key/value

How do I convert ["one","two","three"] into {one:"one", two:"two", three:"three"}
import stringArray from './a.js';
class b {
hashmap = stringArray// convert this into Object here inline.
}
Before you jump I know of for how to achieve this in say constructor() with tricks like forEach, for in loop etc. Is there a simple one line code to achieve this in the class property not inside a function.
Lodash
You can use _.zipObject. It accepts two arrays - one for keys, another for values but if you just use the same array twice you'd get matching pairs:
const arr = ["one","two","three"];
const obj = _.zipObject(arr, arr);
console.log(obj);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
Plain JavaScript
You can use Object.fromEntries to do the same thing. It works with an array of key-value pairs, so you'll have to transform yours to that:
const arr = ["one","two","three"];
const matchingKeyValuePairs = arr.map(x => [x, x]);
const obj = Object.fromEntries(matchingKeyValuePairs);
console.log(obj);
Also you can use Array#reduce to generate an object with a computed property name:
const arr = ["one","two","three"];
const obj = arr.reduce((acc, item) => ({...acc, [item]: item}), {});
console.log(obj);
data = ["one","two","three"];
data = data.map(e => [e,e]) // keyvalue pairs [["one","one"],["two","two"],["three","three"]]
data = Object.fromEntries(data); // {"one":"one","two":"two","three":"three"}
map will convert each element of your input array to a structure you want.
In this case, we want to convert each element to an array with the element repeated twice in it
Object.froEntries will convert a list of key-value pair to an Object
This can be also done with the plain old for loop
data = ["one","two","three"];
obj = {};
for(let i = 0; i < data.length ; i++){
obj[data[i]] = data[i];
}
Try this:
const arr = ["one","two","three"]
let obj = {}
arr.forEach(item => {obj[item] = item})
document.write(JSON.stringify(obj))
Lodash has the _.keyBy() function, that creates an object from an array by generating keys from the values via the function supplied (the iteratee). The default iteratee is _.identity(), which returns the value.
const arr = ["one","two","three"];
const obj = _.keyBy(arr);
console.log(obj);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

Create an array from an object with with key and its suffix

Looking for help to convert/group an object to an array using a key, the key has a difference with its (-)suffix.
const obj = {
"name-1":"a",
"age-1":"20",
"email-1":"a#email.com",
"name-2":"b",
"age-2":"24",
"email-2":"b#email.com",
"name-3":"c",
"age-3":"22",
"email-3":"c#email1.com"
};
Expected result
[
{
"name":"a",
"age":"20",
"email":"a#email.com"
},
{
"name":"b",
"age":"24",
"email":"b#email.com"
},
{
"name":"c",
"age":"22",
"email":"c#email.com"
}
]
Maybe due wrong search keyword unable to find a duplicate question.
You can run a reduce on Object.entries and split the keys say name-1, age-2 etc by '-' and return an array of objects.
const obj = {
"name-1":"a",
"age-1":"20",
"email-1":"a#email.com",
"name-2":"b",
"age-2":"24",
"email-2":"b#email.com",
"name-3":"c",
"age-3":"22",
"email-3":"c#email1.com"
};
const res = Object.entries(obj).reduce((acc, [key, value]) => {
const [ k, i ] = key.split('-');
acc[i - 1] = acc[i - 1] || {};
acc[i-1][k] = value;
return acc;
}, [])
console.log(res);
At the code above inside the reduce I split the key by '-' and it gives me a key of an object and the index of the final array.
Then I check if the index i - 1 exists in the array. If not then initialized it by an empty object. Here I use i - 1 because the given object keys are starting from 1 but an array starts from 0.
Finally, I put the object value into the newly created object.
This is a nice algorithm question that I will resolve by writing it with ES6 syntax.
You can achieve this thanks to some functions such as Object.entries and reduce
Example:
const obj = {
"name-1":"a",
"age-1":"20",
"email-1":"a#email.com",
"name-2":"b",
"age-2":"24",
"email-2":"b#email.com",
"name-3":"c",
"age-3":"22",
"email-3":"c#email1.com"
};
const result = Object.entries(obj)
// Here we destructure the entry with on the left the key, and value on the right
.reduce((accumulator, [key, value]) => {
const [property, index] = key.split('-');
// Get the value currently being filled, or an empty object if it doesn't
// exist yet.
const entry = accumulator[index] || {};
accumulator[index] = {
// Spread the current entry to which we are adding
// the property to the object being filled
...entry,
// Dynamic key syntax
[property]: value,
};
return accumulator;
}, [])
// Remove "holes" from the array since it's indexed with given keys
.filter(value => value !== undefined);
console.log(result);

Convert JSON to Array of Objects using lodash

I have a JSON object in NoSql database in this format. We are getting this data after migrating some records from some other database and these are multi-valued fields.(Basically we are trying to clean the data for further processing).
{
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
}
I want to add another key "bpTableDataName" in the same JSON which should have this format and values,
"bpTableDataName": [
{
"name": "aName",
"email": "aEmail",
"pwdid": "aPWID"
},
{
"name": "bName",
"email": "bEmail",
"pwdid": "bPWID"
},
{
"name": "cName",
"email": "cEmail",
"pwdid": "cPWID"
}
],
Is there a way we can achieve this using lodash?
Try following code -
o = {
"BPContName": "aName;bName;cName",
"BPContEmail": "aEmail;bEmail;cEmail",
"BPContPWID": "aPWID;bPWID;cPWID"
}
map = { "BPContName" : "name", "BPContEmail": "email", "BPContPWID": "pwdid" }
const result = _.reduce(o, (arr, v, k) => ( v.split(";").forEach((x,i) => _.set(arr, `${i}.${map[k]}`, x)), arr ), [])
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>
You can use split() to split the values into an array.
Then iterate over the array and create the require json and then push that into results.
Check this out.
var data = {
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
}
var names = data.BPContName.split(';');
var emails = data.BPContEmail.split(';');
var pwids = data.BPContPWID.split(';');
var results = [];
for(var i = 0 ; i < names.length; i++) {
var obj = {
name: names[i],
email: emails[i],
pwdid: pwids[i]
}
results.push(obj);
}
console.log(results)
You could reduce the entries returned by Object.entries like this:
let obj = {
"BPContName": "aName;bName;cName",
"BPContEmail": "aEmail;bEmail;cEmail",
"BPContPWID": "aPWID;bPWID;cPWID"
}
let bpTableDataName = Object.entries(obj).reduce((r, [key, value]) => {
let splits = value.split(";");
key = key.replace("BPCont", "").toLowerCase();
splits.forEach((split, i) => (r[i] = r[i] || {})[key] = split)
return r;
}, [])
obj.bpTableDataName = bpTableDataName;
console.log(obj)
Object.entries returns an array of key-value pair. Loop through each of them
split the each value at ;
get the key by removing BPCont part and making it lowerCase
Loop through the splits and update specific keys of objects at each index
Update:
Since you have an extra d in the output's key, you can create a mapping object:
propertyMap = {
"BPContName": "name",
"BPContEmail": "email",
"BPContPWID": "pwdid"
}
And inside the reduce, change the replace code to this:
key = propertyMap[key]
Using Object.assign, Object.entries, Array#map and the spread operator make this trivial
const inputdata = {
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
};
const t1=Object.assign({},...Object.entries(inputdata).map(([k,v])=>({[k]:v.split(';')})));
inputdata.bpTableDataName=t1.BPContName.map((name,i)=>({name,email:t1.BPContEmail[i],pwdid:t1.BPContPWID[i]}));
console.log(inputdata);
Of course, it wouldn't be me without a one-liner
const obj = {
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
};
// one line to rule them all
obj.bpTableDataName=Object.entries(obj).reduce((r,[k,v])=>(v.split(';').forEach((v,i)=>(r[i]=r[i]||{})[{BPContName:'name',BPContEmail:'email',BPContPWID:'pwdid'}[k]]=v),r),[]);
//
console.log(obj);
Basically what you need is to zip it.
Snippet:
let obj = {"BPContName":"aName;bName;cName","BPContEmail":"aEmail;bEmail;cEmail","BPContPWID":"aPWID;bPWID;cPWID"},
res = _.zipWith(
..._.map(obj, v => v.split(';')),
(name, email, pwid) => ({name, email, pwid})
);
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Note, the sequence of the parameters we have to put such a way, the original object give us values when using Object.values or giving us keys when using Object.keys usually it is alphabetical order. But, In case in any env the order is not guranted we can sort it with a sequence of keys as a metadata.
Or else you can explicitly pass the arguments like:
(obj.BPContName.split(';'), obj.BPContEmail.split(';'), obj.BPContPWID.split(';'))
You can use lodash's _.flow() to create a function. Use _.map() with _.overArgs() to create a function that splits the values, format the key, and then converts them to an array of pairs using _.unzip(), for example [['name', 'x'], ['name', 'y']]. Transpose the array of arrays with _.unzip() to combine pairs of different properties. Then use _.map() to iterate, and convert each array of pairs to an object using _.fromPairs().
const { flow, partialRight: pr, map, unzip, overArgs, times, size, constant, split, fromPairs } = _
const keysMap = new Map([['BPContName', 'name'], ['BPContEmail', 'email'], ['BPContPWID', 'pwdid']])
const formatKey = key => keysMap.get(key)
const splitVals = pr(split, ';')
const fn = flow(
pr(map, overArgs(
(vals, k) => unzip([vals, times(size(vals), constant(k))]),
[splitVals, formatKey])
),
unzip, // transpose
pr(map, fromPairs) // convert each pairs array to object
)
const data = {
"BPContName":"aName;bName;cName",
"BPContEmail":"aEmail;bEmail;cEmail",
"BPContPWID":"aPWID;bPWID;cPWID"
}
const results = fn(data)
console.log(results)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

splitting string into an object JavaScript

I have this String result:tie,player:paper,computer:paper
I guess you could split into arrays and make a object and parse it an object, however this does not seem to be a good approach.
How would I get this String as a object?
let string = "result:tie,player:paper,computer:paper"
For this particular string, I'd turn the string into proper JSON by surrounding the keys and values with "s, and then use JSON.parse:
const string = "result:tie,player:paper,computer:paper";
const json = '{' + string.replace(/(\w+):(\w+)/g, `"$1":"$2"`) + '}';
console.log(JSON.parse(json));
Though, ideally, whatever serves you that string should be giving you something in JSON format, rather than forcing you to resort to a hacky method like this to deal with a broken input.
Split on ,, iterate through, and split each string on : and make an object key/value property based on that. Use destructuring for simplicity:
let string = "result:tie,player:paper,computer:paper";
let obj = {};
let propsArr = string.split(",");
propsArr.forEach(s => {
var [key, value] = s.split(":");
obj[key] = value;
});
console.log(obj);
Split on the , to get key:value tokens, split those by : to get the key and value, and add them to the reduced object that collects the key value pairs.
var temp = "result:tie,player:paper,computer:paper";
var obj = temp.split(',').reduce((result, token)=>{
var [key, value] = token.split(':');
result[key] = value;
return result;
}, {});
console.log(obj);

Mapping object to key=value string in one line

Is there a way to convert this object:
{
lang: 'en-us',
episode: 12
}
To a string with the following format?
"lang=en-us&episode=12"
Much like mapping an object to a query string, where each property is a query parameter.
I can do it like this:
var parameters = [];
for(var prop in obj)
parameters.push(prop + '=' + obj[prop]);
return parameters.join('&');
But I was looking for a one-line solution. Is this possible?
PS: I cannot use jQuery and any of it utility functions. The solution must be in pure JavaScript.
You can use Array.prototype.map on the Object.keys array:
var data = {"lang": "en-us", "episode": 12};
var str = Object.keys(data).map(function (key) {
return "" + key + "=" + data[key]; // line break for wrapping only
}).join("&");
console.log(str);
With ES6, this becomes even more terse:
var data = {"lang": "en-us", "episode": 12};
var str = Object.keys(data).map(key => `${key}=${data[key]}`).join("&");
console.log(str);
You could use
var myObj ={"lang": "en-us", "episode": 12};
var str = Object.keys(myObj).map(key => key+"="+myObj[key]).join("&");
Whether or not this is any more readable is another question :)
All the other answers work perfectly,
However I've found that you can use URLSearchParams for the same thing...
var myObj = {keyOne: 'keyOneValue', keyTwo: 'keyTwoValue'};
var queryParams = new URLSearchParams(myObj).toString();
console.log(queryParams);
// keyOne=keyOneValue&keyTwo=keyTwoValue
see: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
Object.entries (ES6)
Object.entries returns [key, value] pairs, so we can destructure and map the pairs directly into ${key}=${value}:
Object.entries(params).map(([key, value]) => `${key}=${value}`).join('&');
// "lang=en-us&episode=12"
URLSearchParams
For the specific use case of query strings, use URLSearchParams.toString:
let searchParams = new URLSearchParams(params);
searchParams.toString();
// "lang=en-us&episode=12"
URLSearchParams provides an interface with common utility methods, e.g.:
searchParams.get('episode');
// "12"
searchParams.sort();
// "episode=12&lang=en-us"
searchParams.set('episode', 123456);
// "episode=123456&lang=en-us"
If the value contains equalTo (=) symbol, the accepted solution will not work.
Example
key1=a,key2=b,keyc=keyof=thec
accesskey=absdsfdfsa===
Solution:
Better to use Regex,
const a =
'AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;DefaultEndpointsProtocol=http;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1';
const output = {};
a.split(';').forEach((v, i) => {
const [key, value] = v.split(RegExp(/=(.*)/));
output[key] = value;
})
console.log(output);
output
Note: AccountKey contains == in value
{
AccountName: 'devstoreaccount1',
AccountKey: 'Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==',
DefaultEndpointsProtocol: 'http',
BlobEndpoint: 'http://127.0.0.1:10000/devstoreaccount1',
QueueEndpoint: 'http://127.0.0.1:10001/devstoreaccount1',
TableEndpoint: 'http://127.0.0.1:10002/devstoreaccount1'
}

Categories