Can't access object's properties by argument of a function - javascript

Why array[i].key (where key === "surname") within the function doesn't work,
meanwhile array[i].surname works perfectly?
let objects = [
{ name: 'Jack', surname: 'Jackson' },
{ name: 'Ivar', surname: 'Bjornsson' },
{ name: 'John', surname: 'Mickelson' }
];
function sort (array, key) {
for (let i = 0; i < array.length; i++) {
console.log(array[i].key)// Somehow the "key", which is equal to "surname" doesn't work;
// here will be undefined;
console.log(array[i].surname)//But here writing 'surname' directly works fine;
// the correct answer will be there;
console.log(key)// However, key === surname
}
}
sort(objects, 'surname');

You have to access the property with square brackets:
let objects = [
{ name: 'Jack', surname: 'Jackson' },
{ name: 'Ivar', surname: 'Bjornsson' },
{ name: 'John', surname: 'Mickelson' }
];
function sort (array, key) {
for (let i = 0; i < array.length; i++) {
console.log(array[i][key])// Somehow the "key", which is equal to "surname" doesn't work;
// here will be undefined;
console.log(array[i].surname)//But here writing 'surname' directly works fine;
// the correct answer will be there;
console.log(key)// However, key === surname
}
}
sort(objects, 'surname');
This
array[i].key
is equivalent to
array[i]['key']

Related

Best way to replace an array with its contents from inside an object

I'm given the following JavaScript object:
{
name: [
{
"firstName":"First ",
"lastName":"Last"
}
],
age: 21
}
The name property (or other similar complex props) are always provided as an object within an array, even though there can only ever be a single value.
I need to save the information as an object that looks like this (without the array around the value of the name property):
{
name: {
firstName: 'First ',
lastName: 'Last'
},
age: 21
}
I need a generic function that doesn't reference a particular property name because that changes depending on the query. Here's my solution:
const object = {
name: [{"firstName":"First ","lastName":"Last"}],
age: 21
}
const data = {}
for (const property in object) {
const value = object[property]
if (Array.isArray(value)) {
data[property] = value[0]
} else {
data[property] = value
}
}
Which returns the properly formatted object.
My question is whether this is the most performant and/or most obvious way to get the result I'm looking for?
If you want abstraction over the entire object you could do something like this:
const object1 = {
name: [{"firstName":"First ","lastName":"Last"}],
age: 21
}
const rebuildObject = (object) => Object.keys(object).reduce((result, key) => {
const value = object[key];
result[key] = Array.isArray(value) ? object[key][0] : value;
return result;
}, {});
const newObject = rebuildObject(object1);
console.log(newObject);
If the name array is guaranteed to only ever have 1 object inside of it and is always an array, you can do:
const data = {
name: [
{
"firstName":"First ",
"lastName":"Last"
}
],
age: 21
};
if(data.name.length === 0) {
const newObj = {
name: data.name[0],
age: data.age
};
};
console.log(newObj); // { firstName: 'First ', lastName: 'Last', age: 21 }
Edit
When name is actually any arbitray key name, you can do:
const data = {
name: [
{
"firstName":"First ",
"lastName":"Last"
}
],
age: 21
};
const objKeys = Object.keys(data);
console.log(objKeys) // > Array ["name", "age"]
let arbKey = objKeys.filter(objKey => objKey !== "age")[0];
console.log(arbKey); // > "name"
const newObj = {
arbKey: data[arbKey][0],
age: data.age
};
console.log(newObj); // > Object { arbKey: Object { firstName: "First ", lastName: "Last" }, age: 21 };
Note: This only works based on the object schema you have provided. If your actual code is different, you will need to tweak it.
this is a generic function that can serve what you need, call the function with the object and property name you want to transform.
function arrayToObject(object, property) {
if(object[property] && Array.isArray(object[property])) {
object[property] = object[property][0];
}
return object;
}
// let data = {
// name: [
// {
// "firstName":"First ",
// "lastName":"Last"
// }
// ],
// age: 21
// }
// console.log(arrayToObject(data, 'name'));
// { name: { firstName: 'First ', lastName: 'Last' }, age: 21 }
update:
in case we don't know the property name,
we can use this version.
function arrayToObject(object) {
for(let key in object){
if(Array.isArray(object[key])) {
object[key] = object[key][0];
}
}
return object;
}
let a = {
name: [
{
"firstName":"First ",
"lastName":"Last"
}
],
age: 21
}
a.name = a.name[0];

Having trouble finding value with for-in loop

I am attempting to loop through this array's objects elements and return 'gotcha, bill' when the 'for in' loop finds the value 'bill'. However, it only seems to return 'not him' four times. I've skimmed over it several times and I'm not sure what I am missing. This is my first time using a for in loop, so I could be misunderstanding how it works.
Any help would be appreciated!
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
for(let i = 0; i < array.length; i++) {
for(let key in array[i]) {
if(key === 'bill') {
return console.log('gotcha, bill');
} else {
console.log('not him');
}
}
}
}
findBill(names)
for..in iterates over an object's keys. Since bill is a value, not a key, the (key === 'bill') test will never evaluate to true.
If you wanted to iterate over the object's values instead, use Object.values, and since it sounds like you want to find the bill object, you can use .find:
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
return array.find((obj) => (
Object.values(obj).includes('bill')
))
};
console.log(findBill(names))
If you know in advance that the value will be in the name property, then just test that property, rather than using Object.values:
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
return array.find((obj) => (
obj.name === 'bill'
))
};
console.log(findBill(names))
Here. I changed your for loop to forEach but that is not the main thing that solves your problem. It is how you access the object's property. I use forEach because it will be easier (for me) to get the desired data from the object.
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
array.forEach(function(person){
if(person.name === 'bill') {
return console.log('gotcha, bill');
} else {
console.log('not him');
}
});
}
findBill(names)
And this is how it should be if you insist on using for loop.
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
for(let i = 0; i < array.length; i++) {
if(array[i].name === 'bill') {
return console.log('gotcha, bill');
} else {
console.log('not him');
}
}
}
findBill(names)
key is exactly that--the keys of each object, namely, name or age. You need to actually index into the array at the correct index, then access the value for the key you're inspecting in the loop with if (array[i][key] === 'bill').
Here's a working example:
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
for(let i = 0; i < array.length; i++) {
for(let key in array[i]) {
if(array[i][key] === 'bill') {
return console.log('gotcha, bill');
} else {
console.log('not him');
}
}
}
}
findBill(names);
However, the extra loop isn't necessary and causes logic errors because you might have some other key, say, buffalo that happens to have the value "bill" and you'll wind up with a false positive. You know the key, so you can simply search the array for any object with the matching value for that key:
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
console.log(names.find(e => e.name === "bill"));
Lastly, I recommend avoiding console.log in functions, which is a side effect that limits reusability. console.log returns undefined after printing, so it's misleading to return this, even in simple or contrived examples.
You don't need two loops for this. In fact you can use the Array.find() method to find the object you need and do with it what you need:
const people = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
const findByName = (data, name) => data.find(cur => cur.name === name);
const Bill = findByName(people, 'bill');
if (Bill === null) { console.log(`could not find bill`); }
else { console.log(`bill is ${Bill.age} years old`); }

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.
}

Loop through an array of objects and sort them

I have an array containing some objects and I am trying to loop through it where I have data stored in the following order:
firstName: Alice
lastName: Wonderland
age:12
I am trying to loop, then to sort it in descending order where age: value should be in first position then > lastName: Wonderland comes and lastly firstName.
Here is my code until this moment
var data = {
example1: [{
firstName: 'Alice',
lastName: 'Wonderland',
age: 12
}],
example2: [{
firstName: 'Thomas',
lastName: 'Mathison',
age: 14
}],
example3: [{
firstName: 'David',
lastName: 'Jacobsen',
age: 18
}]
};
for (var key in data) {
var arr = data[key];
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
console.log(prop + ': ' + obj[prop]);
}
}
}
}
I want to achieve the reverse order (descending) when I output the result in the console.log();:
age: 12,
lastName: 'Wonderland',
firstName: 'Alice'
age:14,
lastName: 'Mathison',
firstName: 'Thomas'
age:18,
lastName: 'Jacobsen',
firstName: 'David'
I am not sure about the sort function behavior. How should it work during the loop?
Any suggestions?
var data = {
example1: [{
firstName: 'Alice',
lastName: 'Wonderland',
age: 12
}],
example2: [{
firstName: 'Thomas',
lastName: 'Mathison',
age: 14
}],
example3: [{
firstName: 'David',
lastName: 'Jacobsen',
age: 18
}]
};
var objectArray=[];
for (var key in data) {
var arr = data[key];
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
objectArray.push(obj);
}
}
objectArray.sort(function(element1,element2){
return element2.age - element1.age
}); //now iterate over the array it is sorted in descending order
Sorting arrays of non-primitive data types (custom objects and data structures like in your case) require two steps. It's quite straightforward so follow along.
First you need to create a function capable of comparing two objects of your custom data structure according to your desired criteria.
Second, you provide this decision function to a sort function along with your array and it will use it to sort the array for you. Lets do it for your case:
First the compare function, a and b are objects from your custom structure. returning 1 means object a is "bigger", returning -1 means b is "bigger", returning 0 means that, according to your criteria, both are equal in "size". The order of the if statements bellow is naturally important and reflects the priorities you described:
age takes priority over names and last-name over first-name.
function compare_people(a, b) {
if (a.age < b.age) {
return -1;
}
if (a.age > b.age) {
return 1;
}
if (a.lastName < b.lastName) {
return -1;
}
if (a.lastName > b.lastName) {
return 1;
}
if (a.firstName< b.firstName) {
return -1;
}
if (a.firstName> b.firstName) {
return 1;
}
return 0;
}
Now all you have to do is provide your criteria and array to javascript's sort function. In your case objects are stored inside the data array, so you do:
data.sort(compare_people);
Done, array sorted!
Here you can study the concept more in depth https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Good luck.
Apparently the question is not clear enough, people keep giving you sorting algorithms which I understand it is not what you are looking for, you want to change the internal order of the properties (which makes no sense, they have no 'order' they are part of a map, in any case, here is what I would do:
var data = {
example1: [{
firstName: 'Alice',
lastName: 'Wonderland',
age: 12
}],
example2: [{
firstName: 'Thomas',
lastName: 'Mathison',
age: 14
}],
example3: [{
firstName: 'David',
lastName: 'Jacobsen',
age: 18
}]
};
for (var key in data) {
var arr = data[key];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
newArr.push({
age: obj.age,
firstName: obj.firstName,
lastName: obj.lastName
})
}
data[key] = newArr;
}
But again, what you are trying to do makes no sense, or at least according to the description.
Use [].unshift() method
var result = [];
for (var key in data) {
var arr = data[key];
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
result.unshift(prop + ': ' + obj[prop])
}
}
}
}
console.log(result)
here is demo https://plnkr.co/edit/N4Zt28zh0A3MpwoOrzmZ?p=preview

Update/Create object properties dynamically

I'm creating a feature that provides a get() and set() function to read and update values from a JavaScript object. The trick is that I'm using a dot notated string to specify the properties.
I've got the get() working fine, it's the set() that I'm having troubles with.
Sample data:
var data = {
person: {
name: 'Fred',
birthday: '19840101',
address: {
street: '123 Main St.',
city: 'Anytown',
state: 'NY',
zip: '123123'
},
family: {
spouse: 'Sally',
children: ['Sam', 'Frank', 'Susan']
}
}
};
get() function:
function get (path) {
var parts = path.split('.'),
tmp = data;
for (var i = 0, l = parts.length; i < l; ++i) {
if (tmp[parts[i]]) {
tmp = tmp[parts[i]];
}
else {
tmp = null
break;
}
}
return tmp;
}
console.log(get('person.name')); // Fred
console.log(get('person.family.children')); // ['Sam', 'Frank', 'Susan']
console.log(get('person.jobs.apple')); // null
set() function:
var foo = null;
function set (path, val) {
var parts = path.split('.')
tmp = {},
foo = data;
for (var i = 0, l = parts.length; i < l; ++i) {
if (tmp[parts[i]]) {
tmp = data[parts[i]];
}
else {
tmp = {};
}
if (i+1 === l) {
tmp = val;
}
data[parts[i]] = tmp;
}
}
set('person.name', 'Dave'); // replace existing name
set('person.family.children', ['Tim', 'Matt', 'Kathy']); // replace existing array
set('person.jobs.apple', 'developer'); // should create the necessary properties
console.log(data);
I end up with the following object:
obj = {
person: {},
name: "Dave",
family: {},
children: ["Tim","Matt","Kathy"],
jobs: {},
apple: "developer"
}
Any thoughts on how to accomplish this?
You do not really need any functions at all for this.
See this
var data = {
person: {
name: 'Fred',
birthday: '19840101',
address: {
street: '123 Main St.',
city: 'Anytown',
state: 'NY',
zip: '123123'
},
family: {
spouse: 'Sally',
children: ['Sam', 'Frank', 'Susan']
}
}
};
alert(data.person.name);
data['person']['name'] = 'Tim';
alert(data['person']['name']);
There is also this answer which may help
Javascript object key value coding. Dynamically setting a nested value
It appears that you have some typos in your set code.
The line tmp = data[parts[i]]; should really be tmp = tmp[parts[i]];.
And then you probably want to put that into a new variable - say, newTmp, - so that you can assign it back into the object later:
tmp[parts[i]] = newTmp;
tmp = newTmp;
Your problem seems to be the data[parts[i]] = tmp; at the end of the set function.

Categories

Resources