JavaScript - Altering keys when criteria met - javascript

I want to write a function that takes an array of objects as an argument. If an object in the array contains the key "name," I want to change that key to "title." I then want to return an updated version of the array of objects with all of the keys changed.
This is my attempt at doing this. It's not doing what I want it to.
const people = [{age: 32},{name: 'bob'},{name: 'jack', age: 3}];
function nameToTitle(arr){
let result = [];
for(let i = 0; i < arr.length; i++){
if(arr[i].name){
let newObj = {};
for(let x in arr[i]){
if(arr[i][x] === 'name'){
newObj['title'] = arr[i][x];
}
else {
newObj[x] = arr[i][x];
}
}
result.push(newObj);
}
else {
result.push(arr[i])
}
}
return result;
}
console.log(nameToTitle(people));
This above code returns this:
[ { age: 32 }, { name: 'bob' }, { name: 'jack', age: 3 } ]
=> undefined
It doesn't change the name key to "title."

The code below should work for your use case. Note that I've changed people to a mutable variable (not a const any more). Essentially all this does is iterate over each dictionary in your array, if it finds a dictionary with the "name" key it sets a "title" key with the same value and then deletes the "name" key.
var people = [{age: 32}, {name: 'bob'}, {name: 'jack', age: 3}];
for (var i = 0; i < people.length; i++) {
if (people[i].hasOwnProperty("name")) {
people[i]["title"] = people[i]["name"];
delete people[i]["name"];
}
}
console.log(people);

You are very close, your if-condition is checking the value of your object rather than the key. So all you need to do is change:
if(arr[i][x] === 'name') // 'bob' === 'name' for {name: 'bob'}
to:
if(x === 'name') // 'name' === 'name' for {name: 'bob'}
Because the value of x in for(let x in arr[i]) is the key value that you are iterating.
const people = [{age: 32},{name: 'bob'},{name: 'jack', age: 3}];
function nameToTitle(arr){
let result = [];
for(let i = 0; i < arr.length; i++){
if(arr[i].name){
let newObj = {};
for(let x in arr[i]){
if(x === 'name'){
newObj['title'] = arr[i][x];
}
else {
newObj[x] = arr[i][x];
}
}
result.push(newObj);
}
else {
result.push(arr[i])
}
}
return result;
}
console.log(nameToTitle(people));

you can map over the objects in the array and modify objects that have the name property as shown below
peoples.map(people => {
if(people.hasOwnProperty('name')) {
let title = people.name;
delete people.name;
return Object.assign({}, people, {title: title});
}
return people;
})

const people = [{age: 32},{name: 'bob'},{name: 'jack', age: 3}];
// Copy all properties. If key is 'name' change it to 'title'
const copyObjectWithTitle = obj =>
Object.keys(obj).reduce((objAcc, key) => {
const value = obj[key];
return Object.assign({}, objAcc, key === 'name' ? { title: value} : { [key]: value });
}, {})
// Map over the list. If the object has the key 'name' return a copy with the key 'title'
const nameToTitle = (list) => list.map(obj => obj.hasOwnProperty('name') ? copyObjectWithTitle(obj) : Object.assign({}, obj))
const updatedPeople = nameToTitle(people);

I would do this, if you just want to change the name property to title:
function nameToTitle(objsArray){
var s = objsArray.slice(), a; // make a copy
for(var i in s){
a = s[i];
if(a.name){
s[i].title = a.name; delete s[i].name;
}
}
return s;
}
var objsArray = [{age:32},{name:'bob'},{name:'jack', age:3}];
console.log(nameToTitle(objsArray));

This might get downvoted a bit, but just for fun :]
const people = [{age: 32}, {name: 'bob'}, {name: 'jack', age: 3}];
const result = eval(JSON.stringify(people).replace(/\bname\b/g, 'title'));
console.log(result);

Related

How to convert object keys to upper case

I would like to transform lowercase key to uppercase key. But finding my try not works.
what would be the correct approach?
here is my try:
var obj = {
name: "new name",
age: 33
}
const x = Object.assign({}, obj);
for (const [key, value] of Object.entries(x)) {
key = key.toUpperCase();
}
console.log(x);
Live Demo
With
key = key.toUpperCase();
Reassigning a variable will almost never do anything on its own (even if key was reassignable) - you need to explicitly to mutate the existing object:
var obj = {
name: "new name",
age: 33
}
const x = {};
for (const [key, value] of Object.entries(obj)) {
x[key.toUpperCase()] = value;
}
console.log(x);
You could also use reduce, to avoid the external mutation of x:
var obj = {
name: "new name",
age: 33
}
const x = Object.entries(obj).reduce((a, [key, value]) => {
a[key.toUpperCase()] = value;
return a;
}, {});
console.log(x);

How to transform Array to Object?

What is the best way to transform an array like this:
const arr = [
{ name: 'Bob' },
{ name: 'Ben' }
{ name: 'Cole' }
{ name: 'Mary' }
{ name: 'Travis' }
]
to an object like:
const obj = {
'B': ['Bob', 'Ben'],
'C': ['Cole'],
'M': ['Mary'],
'T': ['Travis']
}
Using only vanilla JS
You can use array#reduce. Iterate through each object of your array and then extract out the first letter and add names corresponding to it.
const arr = [{name: 'Bob'}, {name: 'Ben'}, {name: 'Cole'}, {name: 'Mary'}, {name: 'Travis'}],
result = arr.reduce((r,{name}) => {
r[name[0]] = r[name[0]] || [];
r[name[0]].push(name);
return r;
},{});
console.log(result);
Vanilla JS you say? Here you go
let nil = x => x === undefined;
let empty = ([h]) => nil(h);
let first = ([h]) => h;
let last = ([h, ...t]) => empty(t) ? h : last(t);
let map = ([h, ...t], f) => nil(h) ? [] : [f(h), ...map(t, f)];
let reduce = ([h, ...t], f, i) => nil(h) ? i : reduce(t, f, f(i, h));
let tab = (a, f) => map(a, x => [x, f(x)]);
let push = (a, x) => nil(a) ? [x] : [...a, x];
let groupBy = (a, f) => _groupBy(tab(a, f));
let _groupBy = ka => reduce(ka, (g, [x, k]) => ({...g, [k]: push(g[k], x)}), {});
///
const arr = [{ name: 'Bob' },{ name: 'Ben' },{ name: 'Cole' },{ name: 'Mary' },{ name: 'Travis' }]
z = groupBy(map(arr, x => x.name), first)
console.log(z)
No built-ins!
I created an array where the key is the first letter of the name using the reduce function and restructuring the 'name' from the objects. If the key exists in the array the name is pushed (using spread operator). Else, it creates the key with only one element.
const arr = [
{ name: 'Bob' },
{ name: 'Ben' },
{ name: 'Cole' },
{ name: 'Mary' },
{ name: 'Travis' }
];
const obj = arr.reduce((res, {name})=>{
res[name[0]] = res[name[0]] ? [...res[name[0]],name] : [name];
return res;
}, {});
console.log(obj);
I think this thread is missing a non functional answer, so here it is:
const obj = {};
for(const {name} of arr)
(obj[name[0]] || (obj[name[0]] = [])).push({name});
let obj = {};
arr.forEach( e => {
const name = e.name;
if (!obj[name.charAt(0)]) obj[name.charAt(0)] = [];
obj[name.charAt(0)].push(name);
})
I'm generating a new object and adding to it news keys based in the first char of the name values (only if the key hasn't been already added).
Then, I add each value to the key that corresponds.

Get Unique Key-Value count as an object

I've got the following response from the server:
I want to get the unique key with the occurrence count.
In the following format:
0:{"name":"physics 1","count":2}
1:{"name":"chem 1","count":6}
I've already checked How to count the number of occurrences of each item in an array? but that is not I want.
Here is an es6 solution.
const data = [{
id: 0,
name: 'physics 1',
questionId: 1,
questionNr: 1
}, {
name: 'physics 1',
}, {
name: 'chem 1',
}, {
name: 'chem 1',
}, {
name: 'chem 2',
}];
const grouped = data.reduce((groups, cur) => {
const key = cur.name;
groups[key] = (groups[key] || 0) + 1;
return groups;
}, {});
const result = Object.keys(grouped).map(key => ({name: key, count: grouped[key]}));
console.log(result);
You could do it this way:
var source = [
{'section_name': 'test1'},
{'section_name': 'test2'},
{'section_name': 'test1'},
];
var temp = {};
for (var i = source.length - 1; i >= 0; i--) {
var key = source[i].section_name;
if (!temp[key]) {
temp[key] = 0;
}
temp[key] += 1;
}
var keys = Object.keys(temp);
var result = [];
for (var i = keys.length - 1; i >= 0; i--) {
var key = keys[i];
result.push({"name":key,"count":temp[key]});
}
console.log(result);
use this function this uses map and filter
t.reduce((f,l)=>{
var k=f.filter(elem=>elem.section_name==l.section_name);
if(k.length==1) k[0].count++;
else f.push({section_name:l.section_name,count:1})
return f;
},[] )
you can check this against this to verify
var t=[{section_name:"Physics"},{section_name:"Physics"},{section_name:"Chemistry"},{section_name:"Chemistry"},{section_name:"Physics"}]

indexOf method for array of objects in Javascript

I have array of objets like:
var MyArray = [] ,
Person = {},
[
{
name: 'John',
surname: 'Smith',
age: '22'
},
{
name: 'Jesica',
surname: 'Garou',
age: '31'
},
{
name: 'Max',
surname: 'Jolie',
age: '50'
}
]
I want to check , if my data has name 'John' that don't add new person , if not , then add new person with name 'John' and etc.
Thanks in advance .
You could deal with it using Array#find. I assume that you want to mutate your original array.
let arr = [{
name: 'Jesica',
surname: 'Garou',
age: '31'
},
{
name: 'Max',
surname: 'Jolie',
age: '50'
}
];
const obj = {
name: 'John',
surname: 'Smith',
age: '22'
};
const ensure = ({ name, ...z }) => {
if (!arr.find(v => v.name === name)) {
arr.push({ name, ...z });
}
}
ensure(obj);
console.log(arr);
You can use map but you have to know that map iterates through all elements in the array, whereas findIndex returns the first element index that equals the condition and stops the loop.
var MyArray = [
{
name: 'John',
surname: 'Smith',
age: '22'
},
{
name: 'Jesica',
surname: 'Garou',
age: '31'
},
{
name: 'Max',
surname: 'Jolie',
age: '50'
}
];
if(MyArray.findIndex(index => index.name === "John") > -1)
console.log("Found!");
else
console.log("Not found!");
To check if a name already exists in an array, you can make use of array.some function. It will check if name provided already exits or not.
If not then you can write the code to push the object in the array.
I have used the sample names John and Anne. For John, the function isAlreadyPresent returns true. For Anne, it returns false.
let arr = [
{
name: 'John',
surname: 'Smith',
age: '22'
},
{
name: 'Jesica',
surname: 'Garou',
age: '31'
},
{
name: 'Max',
surname: 'Jolie',
age: '50'
}
];
function isAlreadyPresent(name) {
return arr.some(a => a.name === name );
}
console.log('John already exists?',isAlreadyPresent('John'));
console.log('Anne already exists?',isAlreadyPresent('Anne'));
Maybe a name Map could be useful:
var byNam e =new Map(myArray.map(el=>[el.name,el]));
So you can easily do:
if (byName.has("John")){
alert("already exists");
} else {
var obj = { name: "John" };
Map.set(obj.name,obj);
myArray.push(obj);
}
The upper can be achieved with a Set also, but you may also want to do this:
byName.get("John").age=15;
You'll need to loop through all of the objects and check each of their name values. At worst runs in O(n) time.
For example, to check if "John" is a name in the array:
var inArray = false; // Have we found the name in the array yet?
for (var i = 0; i < MyArray.length; i++) { // Loop through the array of objects
if (MyArray[i].name=="John") { // If the name field is equal to "John"
inArray = true; // Name is in the array
break; // Exit the loop
}
}
var searchTerm = "John",
index = -1;
for(var i = 0, len = MyArray.length; i < len; i++) {
if (MyArray[i].name === searchTerm) {
alert("matched string");
index = i;
break;
}
}
You can make a search function like this that:
const index = (array, name) => {
// Search for the string "name" in your array
for (let i in array){
// Look at every element in the array, if an element has the
// corresponding name, return its index
if (array[i].name === name) return i;
}
return -1;
// If you found nothing, return -1
}
let position = index(myArray, "John");
Traditionally we use a constructor to build many similar objects. However, how that is OOP and is out of the scope of what you are asking.
Here we can use a for... in loop to iterate though MyArray, and check that each object does not include the name John.
function addJohn () {
for (let iterator in MyArray) { // You can also use for... of, but it will break in Node.
if (MyArray[iterator].name == "John") {return}; //You can also replace the string with a variable name to check that all objects do not have the variable in them.
else continue;
}
// you can now put in your new object here.
}

Object Splicing within Array not giving correct result

In my application i want to splice objects from an array upon matching, I am using lodash function for splicing like as shown below, unfortunately the json is not splicing correctly,
Working Demo
Can anyone give me some suggestion for this issue
var arr = [{
name: 'Jack',
id: 125
}, {
name: 'Jack',
id: 125
}];
var result = _.without(arr, _.findWhere(arr, {name: 'Jack'}));
console.log(JSON.stringify(result));
Expected result
[]
Actual Result
[{"name":"Jack","id":125}]
Update 1
Even using normal JavaScript way also giving the same output
for(var i = 0; i < arr.length; i++) {
var obj = arr[i];
if(obj.name === 'Jack') {
arr.splice(i, 1);
}
}
#1
var arr = [{
name: 'Jack',
id: 125
}, {
name: 'Jack',
id: 125
}];
var result = _.rest(arr, function (el) {
return el.name === 'Jack';
});
console.log(JSON.stringify(result)); // "[]"
#2
var arr = [{
name: 'Jack',
id: 125
}, {
name: 'Jack',
id: 125
}, {
name: 'foo',
id: 124
}];
var result = _.rest(arr, function (e) {
return e.name === 'Jack';
});
console.log(JSON.stringify(result)); // "[{\"name\":\"foo\",\"id\":124}]"
// 3 also you can use _.filter if you do not want slice of array...
var result = _.filter(arr, function (e) {
return e.name !== 'Jack';
});
console.log(JSON.stringify(result)); // "[{\"name\":\"foo\",\"id\":124}]"
_.findWhere returns only the first matching element. So that you can use _.difference and _.filter or _.rest to do the task
_.difference(arr, _.filter(arr,function(d){ return d.name = 'Jack' }));
You can implement the same using pure javascript using the code below.
for(var i = 0; i < arr.length; i++) {
var obj = arr[i];
if(obj.name === 'Jack') {
arr.splice(i, 1);
i--; // Splicing of elements will cause shifting of indices in the array
}
}

Categories

Resources