I know variations of this question have been asked but bear with me.
I have the following array containing objects (which are routines):
const PREMADE_ROUTINES = [
{
itemIds: ['makebed', 'drinkwater', 'quickstretch', 'hotshower', 'brushteeth', 'smallsnack', 'getdressed', 'todolist', 'declutterinbox',],
routineDuration: DEFAULT_ROUTINE_ITEMS.getItemsFromIds(PASS THIS OBJECTS itemIds HERE)
}
]
How could I access the itemIds in this case within each of the objects in the PREMADE_ROUTINES array?
In this case, I would need to pass the objects itemIds as an argument to the function. I could do this if the object wasn't in an array with a get(). However, I don't know how to do it in this case. Any ideas?
Ideally, I would like to simply access the routineDuration key by looping and simply accessing it.
In your particular context the best solution is to break away the itemIds declaration. This is so you don't run into this issues when populating it later on.
const DEFAULT_ROUTINES = [
...
]
const PREMADE_ROUTINES = [ {
itemIds: DEFAULT_ROUTINES,
routineDuration: yourFunctionHere(DEFAULT_ROUTINES)
]}
I notice your data structure is a bit complex. It might be worth refactoring it, and introducing a couple utility / filtering methods to make your life easier in the future.
You could create a method returning your routines object. That way it'd be more reusable.
const createRoutine = (routines) => ({
itemIds: routines,
routineDurations: getRoutineDurations(routines)
});
const PREMADE_ROUTINES = [
createRoutine(['makebed', 'drinkwater', 'quickstretch']),
createRoutine(['hotshower', 'brushteeth', 'smallsnack']),
];
Related
I'm fetching relational data from my sql database. This data has an identifier (unique/primary key). Sample:
[
{id:1, value:“test“, cat:2},
{id:2, value:“test“, cat:3},
{id:3, value:“test“, cat:4}, ...
]
As proposed on many sites, including Stackoverflow, you may use an array's find function to access the elements by their id:
Find object by id in an array of JavaScript objects
Sample to fetch the value of object with id 3:
SomeVal = myArray.find(x => x.id === 3).value
However, I disagree with this approach. I don't see why you would search for an identifier, as you could just simply access the element directly via id, which really is the idea to use an identifier.
You may argue that the array's find function will just do the job as it's superfast, but that's not good enough in my case as performance has highest priority.
As result, I currently "misuse" the index of the array as identifier number to access the elements directly. Sample:
SomeVal = myArray[3].value
However, I am looking for a more feasable approach in javascript/typescript to access the elements by id directly.
I do not need to create/update/delete the elements, I solely need to access them once fetched.
I must not use arrays at all if another data structure is better for this.
I am NOT proposing to replace an array’s field search function such as find with the direct index access. And the core of the discussion shall not be which array element is accessed by 3, as this is a simple example. The main idea of the question is if it’s feasible to use the index if an array like it was the identifier, hence to use index which directly correlates with the id field.
However, I disagree with this approach. I don't see why you would search for an identifier, as you could just simply access the element directly via id, which really is the idea to use an identifier.
You can't directly access by ID with the structure you've shown. You need a different structure to do that.
As result, I currently "misuse" the index of the array as identifier number to access the elements directly. Sample:
SomeVal = myArray[3].value
That doesn't access the entry with id: 3. It accesses undefined (with your sample data). Indexes start at 0, not 1. Moreover, unless the underlying system guarantees it, you can't rely on the entries being in id order with no gaps, etc.
For access by id, convert the array to a Map or an object. Then you can reuse that map or object and benefit from the sublinear lookup time on the map key / object property name.
Map (I'd recommend this):
// Note that I've put them out of order to demonstrate we're really getting by id
const array = [
{id:2, value:"test", cat:3},
{id:1, value:"test", cat:2},
{id:3, value:"test", cat:4},// ...
];
const map = new Map(array.map(entry => [entry.id, entry]));
console.log(map.get(1));
Object:
// Note that I've put them out of order to demonstrate we're really getting by id
const array = [
{id:2, value:"test", cat:3},
{id:1, value:"test", cat:2},
{id:3, value:"test", cat:4},// ...
];
const obj = Object.fromEntries(array.map(entry => [entry.id, entry]));
console.log(obj[1]);
The reason you have to use find in this case is because you have an array of objects. So you cannot directly access the id key.
If you want to access the id key directly, then you need to convert your array to an object.
In my opinion, there are two approaches to do that.
Using a data structure algorithm such as HashTable to find the element easily and in fast time.
Create an object that id is key and its value is the entity object. something like this:
const myArray = [...];
const cachedMyArray = cacheData(myArray);
const anItem = cachedMyArray[3]
// Caching data to find elements fastest
interface MyArray {
...
}
function cacheData(array: MyArray[]) {
const cached = {};
array.forEach((item: MyArray) => {
cached[item.id] = item;
});
return cached;
}
This is more of a general question than a problem I need solved. I'm just a beginner trying to understand the proper way to do things.
What I want to know is whether or not I should only use objects as prototypes (if that's the correct term to use here) or whether or not it's OK to use them to store things.
As an example, in the test project I'm working on, I wanted to store some images for use later. What I currently have is something like:
var Images = {
james: "images/james.png",
karen: "images/karen.png",
mike: "images/mike.png"
};
Because I would know the position, I figure I could also put them in an array and reference the position in the array appropriately:
var images = ["images/james.png", "images/karen.png", "images/mike.png"];
images[0];
Using the object like this works perfectly fine but I'm wondering which is the more appropriate way to do this. Is it situational? Are there any performance reasons to do one over the other? Is there a more accepted way that, as a new programmer, I should get used to?
Thanks in advance for any advice.
Introduction
Unlike PHP, JavaScript does not have associative arrays. The two main data structures in this language are the array literal ([]) and the object literal ({}). Using one or another is not really a matter of style but a matter of need, so your question is relevant.
Let's make an objective comparison...
Array > Object
An array literal (which is indirectly an object) has much more methods than an object literal. Indeed, an object literal is a direct instance of Object and has only access to Object.prototype methods. An array literal is an instance of Array and has access, not only to Array.prototype methods, but also to Object.prototype ones (this is how the prototype chain is set in JavaScript).
let arr = ['Foo', 'Bar', 'Baz'];
let obj = {foo: 'Foo', bar: 'Bar', baz: 'Baz'};
console.log(arr.constructor.name);
console.log(arr.__proto__.__proto__.constructor.name);
console.log(obj.constructor.name);
In ES6, object literals are not iterable (according to the iterable protocol). But arrays are iterable. This means that you can use a for...of loop to traverse an array literal, but it will not work if you try to do so with an object literal (unless you define a [Symbol.iterator] property).
let arr = ['Foo', 'Bar', 'Baz'];
let obj = {foo: 'Foo', bar: 'Bar', baz: 'Baz'};
// OK
for (const item of arr) {
console.log(item);
}
// TypeError
for (const item of obj) {
console.log(item);
}
If you want to make an object literal iterable, you should define the iterator yourself. You could do this using a generator.
let obj = {foo: 'Foo', bar: 'Bar', baz: 'Baz'};
obj[Symbol.iterator] = function* () {
yield obj.foo;
yield obj.bar;
yield obj.baz;
};
// OK
for (const item of obj) {
console.log(item);
}
Array < Object
An object literal is better than an array if, for some reason, you need descriptive keys. In arrays, keys are just numbers, which is not ideal when you want to create an explicit data model.
// This is meaningful
let me = {
firstname: 'Baptiste',
lastname: 'Vannesson',
nickname: 'Bada',
username: 'Badacadabra'
};
console.log('First name:', me.firstname);
console.log('Last name:', me.lastname);
// This is ambiguous
/*
let me = ['Baptiste', 'Vannesson', 'Bada', 'Badacadabra'];
console.log('First name:', me[0]);
console.log('Last name:', me[1]);
*/
An object literal is extremely polyvalent, an array is not. Object literals make it possible to create "idiomatic" classes, namespaces, modules and much more...
let obj = {
attribute: 'Foo',
method() {
return 'Bar';
},
[1 + 2]: 'Baz'
};
console.log(obj.attribute, obj.method(), obj[3]);
Array = Object
Array literals and object literals are not enemies. In fact, they are good friends if you use them together. The JSON format makes intensive use of this powerful friendship:
let people = [
{
"firstname": "Foo",
"lastname": "Bar",
"nicknames": ["foobar", "barfoo"]
},
{
"firstName": "Baz",
"lastname": "Quux",
"nicknames": ["bazquux", "quuxbaz"]
}
];
console.log(people[0].firstname);
console.log(people[0].lastname);
console.log(people[1].nicknames[0]);
In JavaScript, there is a hybrid data structure called array-like object that is extensively used, even though you are not necessarily aware of that. For instance, the good old arguments object within a function is an array-like object. DOM methods like getElementsByClassName() return array-like objects too. As you may imagine, an array-like object is basically a special object literal that behaves like an array literal:
let arrayLikeObject = {
0: 'Foo',
1: 'Bar',
2: 'Baz',
length: 3
};
// At this level we see no difference...
for (let i = 0; i < arrayLikeObject.length; i++) {
console.log(arrayLikeObject[i]);
}
Conclusion
Array literals and object literals have their own strengths and weaknesses, but with all the information provided here, I think you can now make the right decision.
Finally, I suggest you to try the new data structures introduced by ES6: Map, Set, WeakMap, WeakSet. They offer lots of cool features, but detailing them here would bring us too far...
Actually, the way you declared things brings up the "difference between associative arrays and arrays".
An associative array, in JS, is really similar to an object (because it's one):
When you write var a = {x:0, y:1, z:3} you can access x using a.x(object) or a["x"](associative array).
On the other hand, regular arrays can be perceived as associative arrays that use unsigned integers as ID for their indexes.
Therefore, to answer your question, which one should we pick ?
It depends : I would use object whenever I need to put names/labels on thing (typically not for a collection of variables for instance). If the type of the things you want to store is homogeneous you will probably use an array (but you can still go for an object if you really want to), if some of/all your things have a different type than you should go for an object (but in theory you could still go for an array).
Let's see this :
var a = {
x:0,
y:0,
z:0
}
Both x,y,z have a different meaning (components of a point) therefore an object is better (in terms of semantic) to implement a point.
Because var a = [0,0,0] is less meaningful than an object, we will not go for an array in this situation.
var storage = {
one:"someurl",
two:"someurl2",
three:"someurl3",
}
Is correct but we don't need an explicit name for every item, therefore we might choose var storage = ["someurl","someurl2","someurl3"]
Last but not least, the "difficult" choice :
var images = {
cathy: "img/cathy",
bob: "img/bob",
randompelo: "img/randompelo"
}
and
var images = ["img/cathy","img/bob","img/randompelo"]
are correct but the choice is hard. Therefore the question to ask is : "Do we need a meaningful ID ?".
Let's say we work with a database, a meaningful id would be better to avoid dozens of loops each time you wanna do something, on the other hand if it's just a list without any importance (index is not important, ex: create an image for each element of array) maybe we could try and go for an array.
The question to ask when you hesitate between array and object is : Are keys/IDs important in terms of meaning ?
If they are then go for an object, if they're not go for an array.
You're correct that it would be situational, but in general its not a good idea to limit your program by only allowing a finite set of supported options like:
var Images = {
james: "images/james.png",
karen: "images/karen.png",
mike: "images/mike.png"
};
Unless, of course, you happen to know that these will be the only cases which are possible - and you actively do not want to support other cases.
Assuming that you dont want to limit the possibilities, then your array approach would be just fine - although personally I might go with an array of objects with identifiers, so that you arent forced to track the index elsewhere.
Something like:
var userProfiles = [
{"username": "james", "image": "images/james.png"},
{"username": "karen", "image": "images/karen.png"},
{"username": "mike", "image": "images/mike.png"}
];
I'm trying to get my head around how to use Immutables in JavaScript/TypeScript without taking all day about it. I'm not quite ready to take the dive into Immutable.js, because it seems to leave you high and dry as far as type safety.
So let's take an example where I have an Array where the elements are all of Type MyType. In my Class, I have a method that searches the Array and returns a copy of a matching element so we don't edit the original. Say now that at a later time, I need to look and see if the object is in the Array, but what I have is the copy, not the original.
What is the standard method of handling this? Any method I can think of to determine whether I already have this item is going to take some form of looping through the collection and visiting each element and then doing a clunky equality match, whether that's turning both of them to strings or using a third-party library.
I'd like to use Immutables, but I keep running into situations like this that make them look pretty unattractive. What am I missing?
I suspect that my solution is not "...the standard method of handling this." However, I think it at least is a way of doing what I think you're asking.
You write that you have a method that "...returns a copy of a matching element so we don't edit the original". Could you change that method so that it instead returns both the original and a copy?
As an example, the strategy below involves retrieving both an original element from the array (which can later be used to search by reference) as well as a clone (which can be manipulated as needed without affecting the original). There is still the cost of cloning the original during retrieval, but at least you don't have to do such conversions for every element in the array when you later search the array. Moreover, it even allows you to differentiate between array elements that are identical-by-value, something that would be impossible if you only originally retrieved a copy of an element. The code below demonstrates this by making every array element identical-by-value (but, by definition of what objects are, different-by-reference).
I don't know if this violates other immutability best practices by, e.g., keeping copies of references to elements (which, I suppose, leaves the code open to future violations of immutability even if they are not currently being violated...though you could deep-freeze the original to prevent future mutations). However it at least allows you to keep everything technically immutable while still being able to search by reference. Thus you can mutate your clone as much as you want but still always hold onto an associated copy-by-reference of the original.
const retrieveDerivative = (array, elmtNum) => {
const orig = array[elmtNum];
const clone = JSON.parse(JSON.stringify(orig));
return {orig, clone};
};
const getIndexOfElmt = (array, derivativeOfElement) => {
return array.indexOf(derivativeOfElement.orig);
};
const obj1 = {a: {b: 1}}; // Object #s are irrelevant.
const obj3 = {a: {b: 1}}; // Note that all objects are identical
const obj5 = {a: {b: 1}}; // by value and thus can only be
const obj8 = {a: {b: 1}}; // differentiated by reference.
const myArr = [obj3, obj5, obj1, obj8];
const derivedFromSomeElmt = retrieveDerivative(myArr, 2);
const indexOfSomeElmt = getIndexOfElmt(myArr, derivedFromSomeElmt);
console.log(indexOfSomeElmt);
The situation you've described is one where a mutable datastructure has obvious advantages, but if you otherwise benefit from using immutables there are better approaches.
While keeping it immutable means that your new updated object is completely new, that cuts both ways: you may have a new object, but you also still have access to the original object! You can do a lot of neat things with this, e.g. chain your objects so you have an undo-history, and can go back in time to roll back changes.
So don't use some hacky looking-up-the-properties in the array. The problem with your example is because you're building a new object at the wrong time: don't have a function return a copy of the object. Have the function return the original object, and call your update using the original object as an index.
let myThings = [new MyType(), new MyType(), new MyType()];
// We update by taking the thing, and replacing with a new one.
// I'll keep the array immutable too
function replaceThing(oldThing, newThing) {
const oldIndex = myThings.indexOf(oldThing);
myThings = myThings.slice();
myThings[oldIndex] = newThing;
return myThings;
}
// then when I want to update it
// Keep immutable by spreading
const redThing = myThings.find(({ red }) => red);
if (redThing) {
// In this example, there is a 'clone' method
replaceThing(redThing, Object.assign(redThing.clone(), {
newProperty: 'a new value in my immutable!',
});
}
All that said, classes make this a whole lot more complex too. It's much easier to keep simple objects immutable, since you could simple spread the old object into the new one, e.g. { ...redThing, newProperty: 'a new value' }. Once you get a higher than 1-height object, you may find immutable.js far more useful, since you can mergeDeep.
I am using console.log('errors: ' + password.get('errors')); to see what is returned from password.get('errors')); and in the console this is returned:
List [ Map { "id": "validation.password.tooLong", "defaultMessage": "La password deve avere massimo {max} caratteri", "values": Map { "max": 16 } } ]
I want to access the element "validation.password.tooLong" from this mapped array, I am unsure how exactly to do this. I am not 100% sure this is a mapped array, I am assuming it is though because of the [Map... above.
I assume that you are using immutable.js, thus to get the desired data you need to access this property via methods of these classes:
const errors = password.get('errors');
const errorId = errors.get(0).get('id');
In other answers, you got an undefined because List is an instance of class List, that haven't property 0, but have a method get that returns a value from an array, that stored in the closure. It's a special solution to prevent mutating and ensure immutability (if you want to update value, you should use set(0, value) instead of myList[0] = value, so there is no access via [0]). The same thing with the Map (Map is an immutable object, that stores key: value).
You can learn more about it here: Immutable.js docs (but I'm not sure you have exactly immutable.js, there are many similar libraries, so take a look what do you use exactly).
You can try with below code:
var response = password.get('errors');
var result = response[0]['id'];
To get the value from map you need to use get() function like
var res = password.get('errors');
var ans = res[0].get('id');
When I running this code by node app.js
'use strict';
var data = {"456":"First","789":"Second","123":"Third"};
console.log(data);
I've geting next result:
{ '123': 'Third', '456': 'First', '789': 'Second' }
Why JS or Node.js (I don't know who) sort this object by keys? I don't want this.
What you're seeing is a behavior of the V8 JavaScript engine. It's not something specified by the JavaScript specification, and it's not something you can rely on (most engines don't do that).
But the important thing here is: There is no order to a JavaScript object. So V8's behavior is just as correct as putting those keys in any other order. If you want things in a particular order, you have to use an ordered container, like an array.
JavaScript objects aren’t ordered. If you want things in order, you can use an array.
var data = [
{ key: "456", value: "First" },
…
];
Or, alternatively, keep the key order in a separate array.
Properties in an object aren't ordered. You can't expect the order you give to be preserved when a representation of your object is built for the console.
The iteration order is implementation dependent. Don't rely on it. If you need some order, use another data structure (for example and array of key-values).
// try this to sort employees by age
employees.sort(function(a, b){
return a.age-b.age
});