Destruct a string from split to named object - javascript

I am investigating how create a named object in one go, using destruct
A search for javascript destruct* split object did not reveal how to directly destruct a string into an object using split.
I do not mean reduce or map but pure destructing
const list = { ..... } = `......`.split(..)
or at least
const rowItem = { ..... } = `......`.split(..)
My initial version works, but there should be a neater way with less steps
The initial split on lines is fine. It is the filling of the list using destruct I am curious about
const rows = `100|Description 1|a|
101|Description 2|a|
102|Description 3|b|`.split("\n")
let list = {}
rows.forEach(row => {
const [ProductId, Description, subCat, ] = row.split("|")
list[ProductId] = {"Description": Description, "subCat": subCat }
})
console.log(list)

You can do something like this with IIFE
const rows = `100|Description 1|a|
101|Description 2|a|
102|Description 3|b|`.split("\n")
let list = {}
rows.forEach(row => {
(([ProductId, Description, subCat]) => (list[ProductId] = {
Description,
subCat
}))(row.split("|"))
})
console.log(list)

You can consider using Object.fromEntries if it's available in your environment
const rows = Object.fromEntries(`100|Description 1|a|
101|Description 2|a|
102|Description 3|b|`
.split("\n")
.map(row => row.split('|'))
.map(([key, Description, subCat]) => [key, { Description, subCat }])
);
console.log(rows);

It is possible to set the property to an existing object while destructuring.
const row = { Description: 'Description 1', subCat: 'a' },
o = { }; // existing object to be updated;
({ Description: o.Description, subCat: o.subCat } = row);
console.log(o)
In your case, you have dynamic id keys, nested property updates and you are destructuring an array instead of an object. It becomes complex, but it is possible to apply the above logic to your code (This is extremely hackish and purely academic. This should never ever be used in an actual code base)
const str = "100|Description 1|a|",
splits = str.split('|'),
list = {};// existing object
({ 0: id, [-1]: list[id]= {}, 1: list[id].Description, 2: list[id].subCat } = splits)
console.log(list)
This destructures the array like an object. It gets the property with key 0 and sets it to the id variable. Then destructure the -1 property. This is non-existent, so the default value is used and list[id] = {} is set.
This is how the transpiled code looks like:
var _str$split = str.split('|');
id = _str$split[0];
list[id] = _str$split[-1] === undefined ? {} : _str$split[-1];
list[id].Description = _str$split[1];
list[id].subCat = _str$split[2];
console.log(list);
Applying this to your original snippet:
const rows = `100|Description 1|a|
101|Description 2|a|
102|Description 3|b|`
let list = {},
id;
rows.split("\n")
.forEach(str => ({
0: id,
[-1]: list[id] = {},
1: list[id].Description,
2: list[id].subCat
} = str.split('|'))
)
console.log(list)
Another option is to use matchAll and Object.fromEntries()
const str = `100|Description 1|a|
101|Description 2|a|
102|Description 3|b|`;
const regex = /(\d+)\|([^|]+)\|(\w+)/g;
const output = Object.fromEntries(
Array.from(
str.matchAll(regex), ([, id, Description, subCat]) => [id, { Description, subCat }]
)
)
console.log(output)
matchAll is still in Draft stage but it is implemented except by IE and Safari. You can easily polyfill it. It is basically looping through exec results

Related

How can I add a string to a string value inside an object?

What im trying to do is to add a string id next to a value inside of an object.
So the object is like this:
["John","Mike"]
An item in the object is generated as soon the user clicks an add button
const handleAddClick = () => {
setLanguage([...language, ""]);
};
const handleItemChanged = (event, index) => {
const value = event.target.value;
const list = [...subtitle];
if (list.filter((f) => f === value).length > 0) {
setErrorValidation("Names cannot be equal!");
} else {
setErrorValidation("");
}
list[index] = value;
setName(list)
};
In the handleItemChanged, I tried to do this, but it didn't work.
let string = "test"
list[index] = value + string;
setName(list)
So what I want is to add a string to a new value that is added to the list
["Johntest", "Miketest"]
How can I solve this?
You can use map before assigning value:
// ... the other code is omitted for the brevity
list.map(item => item + "test")
setName(list)
An example:
let arr = ["John", "Mike"]
arr = arr.map(item => item + " test")
console.log(arr)
Calling setName(list) does not trigger a rerender for the simple reason that list is still the same object. setState will only work if the previous and new value is different. For objects, they are shallowly compared.
That is why it is suggested to create a new array using .map():
let string = "test"
const newList = list.map(e => e+urString)
setName(newList)

Trying to swap key value pairs of an object. Any advices?

Trying to swap key-value pairs of an object!
// an object through we have to iterate and swap the key value pairs
const product = {
id: "FRT34495",
price: 34.56,
nr: 34456,
};
// A function that actually swap them, but don't delete old properties
const change = () => {
for (let key in product) {
const x = key;
key = product[key];
product[key] = x;
}
return product;
};
console.log(change());
//
{
'34456': 'nr',
id: 'FRT34495',
price: 34.56,
nr: 34456,
FRT34495: 'id',
'34.56': 'price'
}
the problem is that I need the object with key-value pairs swapped, but in the same amount, not twice more as we can see above, I need to delete the old ones.
Any advice guys?
Most logically straight-forwarding solution:
Turn object into entries array ([[key1, val1], [key2, val2], ...]) using Object.entries
Swap each of the entries ([[val1, key1], [val2, key2], ...]) using map
Turn back into object using Object.fromEntries
function swapKV (obj) {
const entries = Object.entries(obj)
const swappedEntries = entries.map([k, v] => [v, k])
const swappedObj = Object.fromEntries(swappedEntries)
return swappedObj
}
...or more concise:
const swapKV = obj => Object.fromEntries(Object.entries(obj).map([k, v] => [v, k]))
(Of course, another solution would be to just add if (String(x) !== String(key)) delete product[x] to your code. The condition is there to avoid deleting the entry altogether in case key and value are equal when converted to a string.)
This may help!
const swapKV = (obj) => {
const newObj = {};
for (let val in obj) {
newObj[obj[val]] = val;
}
return newObj;
}
You can also try this:
const swap = (obj) => {
return Object.fromEntries(
Object.entries(obj)
.map((key) => key.reverse())`.concat(Object.entries(obj))`
);
};
If the original object is to be also added to the output, concat can be used. The user asks for a function which also keeps the old properties. Otherwise no need.

Is there a syntactically nice way to find and mutate an object in an array?

I am changing the contents of a note from an array of objects.
Example:
const notes = [
{text:'testText',title:'testTitle',uuid:'12'},
{text:'testText',title:'testTitle',uuid:'21'}
]
And I want to change the second notes title and text based on the given uuid.
Currently this is my solution"
let updatedNote = notes.find((note) => note.uuid === '21');
updatedNote.text = text;
updatedNote.title = title;
updatedNote.tagList = tagList;
updatedNote.tags = tags;
Is there a more clean and efficient way of doing this?
Thank you
Make use of Object.assign which mutates the first argument by assigning the properties of each following argument to this target object ...
const notes = [
{text: 'testText', title: 'testTitle', uuid: '12'},
{text: 'testText', title: 'testTitle', uuid: '21'},
];
const text = 'foo';
const title = 'bar';
const tagList = ['bazbiz', 'buzbaz'];
const tags = 'bazbiz,buzbaz';
Object.assign(
// target object which will be mutated and also is the return value.
notes.find((note) => note.uuid === '21'),
// the source objects which properties will bee assigned to the target object.
{
text,
title,
tagList,
tags,
}
);
console.log('notes[1] :', notes[1]);
.as-console-wrapper { min-height: 100%!important; top: 0; }
You can do something like this if you prefer :
const updatedNote = {
...notes.find((note) => note.uuid === uuid),
text,
title,
tagList,
tags,
};
It can be easily reduced if you don't put the new properties on new lines
If I understood correctly, you are creating a new variable to save the new Note values, if this is really necessary, other than just update, I suppose the find method is Ok and you can pass the values directly through an object (if you must update only this specific properties):
let updatedNote = notes.find((note) => note.uuid === uuid);
updatedNote = {text: "text", title:"title", tagList:"tagList", tags:"tags"}
Or even, if you want to update all properties from that object you can use a for...in statement:
let updatedNote = notes.find((note) => note.uuid === uuid);
let newProps = {text,title,tagList,tags}; //ES6+ Object Literal Declarations
for(let property in updateNote){
updateNote[property] = newProps[property];
}

Reduce with obj key, value not working as expected

I'm trying to dynamically create a sqlite insert string with node. I have:
function update_json_obj_into_table(tablename, obj, search_condition) {
const insertValues = Object.entries(obj).reduce((acc, [k,v]) => acc.push(`${k} = ${v}`), []);
const insertValuesString = Array.prototype.join.call(insertValues, '/');
console.log(insertValuesString);
console.log(`UPDATE ${tablename} SET ${insertValues} WHERE ${search_condition}`);
// db.run(`UPDATE ${tablename} SET ${insertValuesString} WHERE search_condition ;`);
};
When I run it :
const obj = {Code: 'A1'};
update_json_obj_into_table('mytable', obj, 'search_condition')
I get:
UPDATE mytable SET 1 WHERE search_condition.
Obviously the insertValues is not working correctly. I was expecting:
Code = 1
but its coming out as '1' . What am I doing wrong?
.push returns the new length of the array, not the mutated array. While you could put the .push on its own line and return the array on the next line:
function update_json_obj_into_table(tablename, obj, search_condition) {
const insertValues = Object.entries(obj).reduce((acc, [k, v]) => {
acc.push(`${k} = ${v}`);
return acc;
}, []);
const insertValuesString = Array.prototype.join.call(insertValues, '/');
console.log(insertValuesString);
console.log(`UPDATE ${tablename} SET ${insertValues} WHERE ${search_condition}`);
// db.run(`UPDATE ${tablename} SET ${insertValuesString} WHERE search_condition ;`);
};
const obj = {
Code: 'A1'
};
update_json_obj_into_table('mytable', obj, 'search_condition')
It would make a lot more sense to use .map, since the input array and ouput insertValues array are one-to-one:
function update_json_obj_into_table(tablename, obj, search_condition) {
const insertValues = Object.entries(obj)
.map(([k, v]) => `${k} = ${v}`);
const insertValuesString = Array.prototype.join.call(insertValues, '/');
console.log(insertValuesString);
console.log(`UPDATE ${tablename} SET ${insertValues} WHERE ${search_condition}`);
// db.run(`UPDATE ${tablename} SET ${insertValuesString} WHERE search_condition ;`);
};
const obj = {
Code: 'A1'
};
update_json_obj_into_table('mytable', obj, 'search_condition')
That said, dynamically constructed queries like these are rarely a good idea - unless the input is trustworthy, it can compromise your database. Even if the input is trustworthy, it can be inelegant due to delimiter escaping issues, reserved works, and so on. Better to look up how to use prepared statements instead, so that the database driver handles the interpolation of external values.

Issue in removing object using Lodash _remove

I am having an Object:
ids = [ "-LIof_e0hPtXKtkc4Uh9", "-LIjBcGO7m7VQ-B3pfYt" ]
If I Iterate using .map function of lodash
_.map(ids, (userID, key) => {
console.log('Lopping userId',userID);
})
it gives me value of each id.
Now when I am trying to remove it using _remove it is not working as expected.
_.remove(ids, (value, key, obj) => value == idToBeRemoved);
Still there is no difference in ids Object.
I am really new to angular4 and using lodash for the first time.
I just wanted to remove a value from ids object and get the remaining object.
Print of console.
I am using firebase and trying to delete data after retrieving it from firebase :
deleteTransactWith(transactWithKey,transactWithUser) {
let currentUser = this._authService.getLoggedInUser();
console.log(transactWithUser.groups)
console.log(Object.keys(transactWithUser.groups).length)
console.log('key To remove',transactWithKey)
for (var key in transactWithUser.groups) {
if (transactWithUser.groups.hasOwnProperty(key)) {
let group = this.firebase.object(`/url/${currentUser.$key}/${key}`);
group.snapshotChanges().take(1).subscribe((groupData: any) => {
groupData = groupData.payload.toJSON();
//console.log('not removed',groupData.userIds)
console.log('key',transactWithKey)
_.remove(groupData.userIds, (value) => value == transactWithKey);
//_.pull(groupData.userIds, transactWithKey);
console.log('removed',groupData.userIds)
});
}
}
You want _filter instead
const ids = [ "-LIof_e0hPtXKtkc4Uh9", "-LIjBcGO7m7VQ-B3pfYt" ]
const idToBeRemoved = "-LIof_e0hPtXKtkc4Uh9"
const filteredIds = _.filter(ids, function(id) { return id !== idToBeRemoved})
console.log(filteredIds)
You can simply use lodash _.pull
const _ = require("lodash");
const ids = [ "-LIof_e0hPtXKtkc4Uh9", "-LIjBcGO7m7VQ-B3pfYt" ]
const result = _.pull(ids, "-LIjBcGO7m7VQ-B3pfYt" )
console.log(filteredIds)
First find the index of what you are removed item and next pull out from it by _.pullAt(lodash)
let getIndex= _.findIndex(this.images, function(o) { return o.name == img.name; });
let removedImage = _.pullAt(this.images, getIndex) ;

Categories

Resources