Javascript searching task - javascript

Task: You have array with key: value pairs like:
arr = ["x:1", "y:2", "a:5", "x:5", "z:0"]
You must sum all the same keys so it will be:
["x:6","y:2","a:5","z:0"]
on output.
I finish this task but its complicate. I have solved the task but I am looking for a simpler solution
var a = ["x:1", "y:2", "a:5", "x:5", "z:0"]
function saberi(niz) {
let povratni = [];
for (clan of niz) {
let razdvojen = clan.split(":");
let key = razdvojen[0]
let value = razdvojen[1]
let provjera = false
for (let i = 0; i < povratni.length; i++) {
let razdvojen2 = povratni[i].split(":")
let key2 = razdvojen2[0]
let value2 = razdvojen2[1]
if (key2 == key) {
console.log("uso")
let novavrijednost = parseFloat(value) + parseFloat(value2)
povratni[i] = key2 + ":" + novavrijednost
provjera = true
break
}
}
if (!provjera) {
povratni.push(clan)
}
}
console.log(povratni)
return povratni
}
saberi(a)

You can use objects to make this easier. Each character to the left of the colon : will be a key in the object, and the number to the right of the colon will be the value, which you can accumulate to the value from the object at the given key.
To start, you can loop through your arr using a for...of loop, and for each string in your array, use .split(":") to break the string into its key and value components. You can then grab the current value stored at the key from the object (grouped) by using grouped[key]. If the value doesn't exist, you can default it to 0 using || 0. Once you have the current value stored in the object, you can add the number version of the value to the accumulated value, and store that new value in the object at the key key.
Once you have your object, you can grab the entries to get an array of the form [[key, value], [key2, value2], ...], which you can use .map() on to convert each [key, value] to a string of the form key:value:
const arr = ["x:1", "y:2", "a:5", "x:5", "z:0"];
const grouped = {};
for(const str of arr) {
const [key, num] = str.split(":");
grouped[key] = (grouped[key] || 0) + Number(num);
}
const res = Object.entries(grouped).map(entry => entry.join(":"));
console.log(res);
The same concept above can be accomplished using .reduce() with a Map instead of an object, as well as Array.from to map the entries of the Map to an array:
const arr = ["x:1", "y:2", "a:5", "x:5", "z:0"];
const res = Array.from(arr.reduce((map, str) => {
const [key, val] = str.split(":");
return map.set(key, (map.get(key) || 0) + +val);
}, new Map), entry => entry.join(':'));
console.log(res);

You could use Array.prototype.reduce() method. Traverse the array and split each item by colon(:). Then group it by key to count sum. At last, transform the object into a key-value pair array using Object.entries() method and then map and join it by colon(:).
const arr = ['x:1', 'y:2', 'a:5', 'x:5', 'z:0'];
const ret = Object.entries(
arr.reduce((prev, c) => {
const p = prev;
const [k, v] = c.split(':');
p[k] = p[k] ?? 0;
p[k] += +v;
return p;
}, {})
).map((x) => x.join(':'));
console.log(ret);

Related

JS split object with key value pairs

I' m trying to write a code which is supposed to convert the array of arrays into an array with objects with key: value pairs inside. I got stuck with the following, where everything is fine besides I'm getting the word keys instead of actual keys inside my objects.
var array = [["white", "goodness"], ["green", "grass"]];
var obj={};
for (var i=0; i<array.length;i++){
for (var z=0; z < 1; z++){
obj[array[i][z]] = array[i][z+1];
}
}
const separateObject = obj => {
const res = [];
const keys = Object.keys(obj);
keys.forEach(key => {
res.push({
keys : obj[key]
});
});
return res;
};
console.log(separateObject(obj));
You need to change the key in the res.push statement to be the variable "key" instead of the string "keys".
res.push({
[key] : obj[key]
});
You can use simple map like:
const array = [
["white", "goodness"],
["green", "grass"]
];
const result = array.map(el => {
return {
[el[0]]: el[1]
};
});
console.log(result);
This works by mapping the array of entries to a new array with the first element of the entry being the key and the second being the value. Destructuring to [key, value] is a bit cleaner and verbose than v[0] and v[1]
const array = [["white", "goodness"], ["green", "grass"]];
const separateObject = arr => {
return arr.map(([key, value]) => ({ [key]: value }));
};
console.log(separateObject(array));

How do I combine/group string values of the same key within an array of objects

If I have an array of objects like:
arr = [{"apple":"sour"}, {"pear":"sweet"}, {"apple":"red"}]
Since arr[0] and arr[2] have the same key, what can I do to combine them separated by a space to form something like:
[{"apple":"sour red"},{"pear":"sweet"}]
const arr = [{"apple":"sour"}, {"pear":"sweet"}, {"apple":"red"}]
// create object
const obj = {}
// iterate through the array
for (const item of arr) {
// get the key e.g. apple
const key = Object.keys(item)[0]
// get the value e.g. sour
const value = item[key]
if (!(key in obj)) {
// create an array for each key
obj[key] = []
}
// push value to the key
obj[key].push(value)
}
// map object to final array
const result = Object.entries(obj).map(([key, value]) => ({ [key]: value.join(' ') }))
console.log(result)
A solution to use reduce to do it
const arr = [{"apple":"sour"}, {"pear":"sweet"}, {"apple":"red"}]
let data = arr.reduce((acc,val) =>{
let key = Object.keys(val)[0]
let obj = acc.find(a => a[key])
if(obj){
obj[key] = obj[key] +" " + val[key]
}else{
acc.push(val)
}
return acc
},[])
console.log(data)

Get Key Value pair after String Split

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

Convert string into key-value pairs in an array

I have a string:
var rrule = "DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1";
I want to convert this string to key-> value pairs in an array.
[
dtstart: 20190514T111500Z,
freq: daily,
interval: 1
]
I know I can take the string and split it based on the semicolon:
var array = rrule.split(";");
... but this leaves me with an array like this:
[
"DTSTART=20190514T111500Z",
"FREQ=DAILY",
"INTERVAL=1"
]
I guess I need another step to map out the keys/values, but I get lost at this point.
Ideally, for the string I want to be able to easily access what dtstarts equals, what interval equals, what other variables equal and so on.
let str = "DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1";
let obj = {};
for (let entry of str.split(";")) {
let pair = entry.split("=");
obj[pair[0]] = pair[1];
}
console.log(obj);
You already know how to split on the ; to get an array, from there you can just aggregate (using reduce) to get an object:
var rrule = "DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1";
var result = rrule.split(";").reduce( (obj,item) => {
let [key,value] = item.split("=");
obj[key] = value;
return obj;
},{});
console.log(result["DTSTART"])
console.log(result["FREQ"])
console.log(result["INTERVAL"])
You were correct to start with split first, this would then return you an array of strings.
To easily convert them, just use map, to return the split the single strings once more, and then return an object based on the property name you would like to give it and it's value
function createKeyValuePairFromString( str ) {
return str.split(';').map( item => {
const splitted = item.split('=');
return { [splitted[0]]: splitted[1] };
});
}
console.log( createKeyValuePairFromString("DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1") );
Use array created and split it again with =
function convertToObject(cookieString) {
const cookieObj = {};
if (!cookieString && typeof cookieString !== 'string') return cookieObj;
const arr = cookieString.split(';');
arr.forEach(record => {
if (record.includes('=')) {
const [key, value] = record.split('=');
cookieObj[key.trim()] = value;
}
});
return cookieObj;
}
You can use it like the code below:
var rrule = "DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1";
let finalObj = {};
rrule.split(';').forEach(i => finalObj[i.split('=')[0]] = i.split('=')[1]);
console.log('finalObj',finalObj);
Here I'm first splitting with ';' so consider the first item to be DTSTART=20190514T111500Z Then on splitting with = I get finalObject['DTSTART'] = 20190514T111500Z
Using forEach()
let str = "DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1";
let obj = {};
let strArr = str.split(';')
strArr.forEach((str) => {
let [key, value] = str.split('=')
obj[key] = value;
});
console.log(obj);
Here's a fairly simple version, returning an object, not an array:
const toObj = str => str
.split (';')
.map ( s => s .split ('=') )
.reduce ( (a, [k, v]) => ({...a, [k]: v}), {} )
let str = "DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1";
console.log (
toObj(str)
)
One of the reasons I like the library is that we can write this sort of logic more simply. In Ramda (disclaimer: I'm one of the authors), it might look like this:
const toObj = pipe ( split (';'), map (split ('=') ), fromPairs)
let str = "DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1";
console.log (
toObj(str)
)
<script src="https://bundle.run/ramda#0.26.1"></script><script>
const {pipe, split, map, fromPairs} = ramda; </script>
var str = "DTSTART=20190514T111500Z;FREQ=DAILY;INTERVAL=1";
// string splitting rule
const rule = (string, delimiter) => string.split(delimiter);
const result = rule(str, ';').reduce((acc, s) => {
const [key, value] = rule(s, '=');
acc[key] = value;
return acc;
}, {});
console.log(result);

What is the most efficent way to filter an object with an array of arrays?

I'm trying to filter an Object by an array of arrays, getting back an array of objects.
Like this:
let obj =
{
"a.1":1,
"a.2":2,
"b.1":3,
"b.2":4,
"c.1":5,
"c.2":6
}
let array =
[
["a.1","b.1"],
["a"],
["b","c.1"]
]
let expectedResult =
[
{
"a.1":1,
"b.1":3,
},
{
"a.1":1,
"a.2":2,
},
{
"b.1":3,
"b.2":4,
"c.1":5
},
]
// this is what I came up with
const filterObjectByArray = (obj, arr) =>
Object.keys(obj)
.filter(ch => {
for (var index = 0; index < arr.length; index++)
if (ch.startsWith(arr[index]))
return true;
})
.reduce((ret, key) =>{
ret[key] = obj[key]
return ret
},{})
let result = array.map(arr => filterObjectByArray(obj, arr))
//kind of deepEqual
console.log(JSON.stringify(expectedResult) == JSON.stringify(result))
Is there a easier or more convenient way to do that? I need to do this operation quite often and my object will be up to couple hundreds entries big, so I see a potential bottleneck here.
I would create a one type mapping of the "base" (the letter) to the "real" keys, and then use it to translate the letter to the real keys when create the object.
const obj = {
"a.1": 1,
"a.2": 2,
"b.1": 3,
"b.2": 4,
"c.1": 5,
"c.2": 6
};
const array = [
["a.1", "b.1"],
["a"],
["b", "c.1"]
];
const getBaseKey = (key) => key.match(/^[a-z]+/)[0]; // get the base of the key - the letter. If it's only one letter, you can use key[0]
/** create a one time map of keys by their base **/
const oobjKeysMap = Object.keys(obj).reduce((map, key) => {
const baseKey = getBaseKey(key);
const curr = map.get(baseKey) || [];
curr.push(key);
return map.set(baseKey, curr);
}, new Map());
const result = array.map((sub) => // iterate the array
[].concat(...sub.map((k) => k in obj ? k : oobjKeysMap.get(getBaseKey(k)))) // create the least of "real" keys
.reduce((ret, key) => { // create the object
ret[key] = obj[key];
return ret;
}, {})
);
console.log(result);

Categories