Clone and update in groovy - javascript

In javascript there is an easy way to generate cloned object with some of the fields updated:
const person = {
isHuman: false,
name: "gabe"
};
const person2 = {
...person1,
name: 'alice'
}
Is there a way to do something like in groovy without copying all the fields manually? I am writing testcases where I wanna generate data with one attribute changed at a time.

Can you use #Immutable(copyWith = true)
#Immutable(copyWith = true)
class Person {
String first, last
}
def tim = new Person('tim', 'yates')
def alice = tim.copyWith(first:'alice')
assert tim.first == 'tim'
assert alice.first == 'alice'
https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/ImmutableBase.html#copyWith

There are many ways this can be done.
One is to construct instances by spreading in a map, e.g., given:
class Person { String name; Boolean isHuman; }
An instance can be constructed using the same spread-map operator I linked to:
m1 = [ name: "Gabe", isHuman: true ]
p1 = new Person(*:m1)
println p1
// Person: Gabe, isHuman=true
This avoids actual work. An exception will be thrown if a map key isn't an instance property.
A utility method grabbing (non-synthetic) prop names from a class, and iterates while putting the name/value pairs into a map is also an option (and affords a bit more safety):
def toMap(obj) {
obj.class.declaredFields
.findAll { !it.synthetic }
.collectEntries { [(it.name): obj."$it.name" ] }
}
Now we can construct a "prototype" object, but override properties:
p2 = new Person(*:toMap(p1), name: "Alice")
println p2
// Person: Alice, isHuman=true
There are also libraries that do this type of work.
Depending on your actual usecase it may not be necessary to do anything other than passing a map, however (duck typing).

Related

HashMap in TypeScript with custom object

Introduction
I am currently work in project that I need to save the score of each user.
For this I used a Map<User, number> to represent it.
Problematic
If I create map with a user named john:
let myMap: Map<User, number> = new Map();
myMap.set(new User("John","Hasherman"), 0);
And if I want to set John Hasherman’s score to 1 (voluntarily using a new instance and not the one previously used), with this code:
myMap.set(new User("John","Hasherman"), 1);
But TypeScript create a new element inside myMap.
Question
So my question is, do you know if it’s possible to customize the comparator used inside the map? like Java when defining hashCode() and equals(o Object)?
You'll need a way for the User to expose functionality that will identify a particular user, perhaps by name, or perhaps by a more unique ID. Either way, a Map where each user is the key isn't very suited to the job, but it's possible.
class User {
public first: string;
public last: string;
constructor(first: string, last: string) {
this.first = first;
this.last = last;
}
}
const myMap: Map<User, number> = new Map();
myMap.set(new User("John","Hasherman"), 0);
// to set John's value to 1:
const foundJohn = [...myMap.keys()].find(
obj => obj.first === 'John' && obj.last === 'Hasherman'
);
if (foundJohn) {
myMap.set(foundJohn, 1);
}
It's somewhat convoluted. I'd suggest considering a different data structure if possible.

difference between spread operator and without the spread in angular

I just have a question about a piece of code that can be done with the spread operator (...) and without the spread operator. But the result stays the same.
exercisesChanged = new Subject<Exercise[]>();
finishedExercisesChanged = new Subject<Exercise[]>();
private availableExercises: Exercise[] = [];
fetchAvailableExercises() {
this.fbSubs.push(this.db
.collection('avaibeleExercises')
.snapshotChanges()
.map(docArray => {
return docArray.map(doc => {
return {
id: doc.payload.doc.id,
name: doc.payload.doc.data()['name'],
duration: doc.payload.doc.data()['duration'],
calories: doc.payload.doc.data()['calories']
};
});
})
.subscribe((exercises: Exercise[]) => {
console.log(exercises);
this.availableExercises = exercises;
this.exercisesChanged.next(this.availableExercises);
console.log(exercises);
}));
}
So it is about this line:
this.exercisesChanged.next(this.availableExercises);
If I just do with the spread operator: ...this.availableExercises or without. The result doesn't change. So what is the benefit of it then?
And I use it in this component:
export class NewTrainingComponent implements OnInit, OnDestroy {
exercises: Exercise[];
exerciseSubscription: Subscription;
constructor(private trainingService: TrainingService) {}
ngOnInit() {
this.exerciseSubscription = this.trainingService.exercisesChanged.subscribe(
exercises => (this.exercises = exercises)
);
this.trainingService.fetchAvailableExercises();
}
}
I will explain everything to you:
Spread operator will copy all of your object {keys,values} (except some advanced types like symboles) and assign it to a new variable (means a new reference or lets say a new memory address reference).
To more clarification: Of course there is a big difference between using spread and without spread operator i will give you an example:
lets say: this.availableExercises has a memory address of 0xAABBCCDD so:
this.exercisesChanged.next(this.availableExercises); ==> this line will pass the 0xAABBCCDD address to the .next(..) method to be handled after by some codes.
but if we use spread operator like:
this.exercisesChanged.next({...this.availableExercises}); ==> this will generate a copy of the {keys,values} means a new object of your previous 0xAABBCCDD addressed object, and assign it to a new reference (new memory address) like 0x99FF1155.
To understand what i meant look at this example:
let myOldReference = this.availableExercises; // memory address: 0xAABBCCDD
this.exercisesChanged.next(myOldReference); // .next(0xAABBCCDD);
let myNewReference = {...this.availableExercises}; // this will generate a copy to a new memory address: 0x99FF115
this.exercisesChanged.next(myNewReference ); // .next(0x99FF115);
so that myOldRefernce !== myNewReference because 0xAABBCCDD is different to 0x99FF115 as references. But keep in mind, this will keep the same {keys, values} because it's a copy of keys values, but with different memory references.
That's why you see the same keys,values, but in backgroud, it's different references.

Store an object with an array inside?

Is there a way to store an object with an array[id] = "certain value", so that every single user has a list of favorite things ?
What I'm trying to achieve is having a data object with undefined values at first, and filling them in, so for example Jack and Sam could have an assigned favorite movie saved.
I tried something like this with no success:
Data.js:
module.exports = function() {
return {
favMovie: ""
}
};
App.js:
var person [] = data();
//1st person
person[811767132257839].favMovie = "Matrix";
//2nd person
person[107230716367889].favMovie = "Kill Bill";
//3rd person
person[973676332752239].favMovie = "Avatar";
...
console.log( "Favorite movie: " + person[id].favMovie );
It doesn't sound like you want any arrays at all, just objects.
// Create an object that we'll keep person objects in
var personData = {};
// Add a person object to it for person ID #123
personData[123] = {};
// Set person #123's favorite movie:
personData[123].favMovie = "Avatar";
// Add a different person; this time, we'll add the movie at
// the same time
personData[234] = {
favMovie: "Matrix"
};
When using objects as maps like that, sometimes people create the objects using Object.create(null) to avoid them having any inherited properties (like toString and valueOf and constructor):
person[123] = Object.create(null);
person[123].favMovie = "Avatar";
In ES2015 (aka "ES6"), you might want to use a Map rather than an object for the map of people:
var personData = new Map();
...and then use set and get for the individual person objects.
If the individual person objects get complicated, you might use a constructor function and associated prototype for them, using either ES5 syntax:
function Person() {
// ...
}
Person.prototype.doSomething = function() {
// ...
};
...or ES2015 syntax:
class Person {
constructor() {
// ...
}
doSomething() {
// ...
}
}
Then creating them:
personData[123] = new Person();
// or if using Map
personData.set(123, new Person());
Side note: Even when we write them as numbers, the keys (property names) in objects are always strings (unless you use ES2015 Symbols, which you probably wouldn't here). In contrast, keys in an ES2015 Map can be anything. Key equality in Map instances is determined using the special "same value zero" algorithm (which is basically === except that NaN is equal to itself [whereas it isn't in ===]).

Generic 2D hash in JavaScript?

In other languages it is possible to create a generic 2D hash. I know creating 2d hashes is possible in javascript as well as explained here, but I can't seem to find a generic way to achieve this.
As an example of what I am looking for. In Ruby you can do this:
2dhash = Hash.new{|h, k| h[k] = Hash.new }
puts 2dhash["test"]["yes"]
#=> nil
2dhash[1][2] = "hello"
puts 2dhash[1][2]
#=> "hello"
Notice that I have not initialized the second level of hash, it happens automatically.
Is it possible to somehow achieve the same in javascript? Specifically, a way to make a 2d hash without initializing the first level of hash (or hard-coding it to be even more specific). The 2dhash will be used dynamically, so I have no clue what the first level will be.
Looks like a nice data structure excercise, let me try :D
function Hash() {
this.hash = {};
}
Hash.prototype.set = function(val) {
var paths = Array.prototype.slice.call(arguments, 1) // all levels
var path = paths.shift() // first level
var hashed = this.hash[path]
if (paths.length) {
// still have deeper levels
if (!(hashed instanceof Hash)) {
hashed = this.hash[path] = new Hash()
}
Hash.prototype.set.apply(hashed, [val].concat(paths))
} else {
// last level
this.hash[path] = val
}
}
Hash.prototype.get = function() {
var paths = Array.prototype.slice.call(arguments, 0) // all levels
var path = paths.shift() // first level
var hashed = this.hash[path]
if (paths.length) {
// still have deeper levels
return Hash.prototype.get.apply(hashed, paths)
} else {
// last level
return hashed
}
}
Now, let's see if it works:
var trytry = new Hash()
trytry.set('the value to store', 'key1', 'key2')
trytry.get('key1') // Hash{key2: 'the value to store'}
trytry.get('key1', 'key2') // 'the value to store'
Hooray it works!
It also works for even deeper levels:
trytry.set('the value to store', 'key1', 'key2','key3', 'key4')
trytry.get('key1', 'key2','key3') // Hash{key4: 'the value to store'}
However, a disadvantage of this approach is that you have to use instance methods get and set, rather than native object literal getter/setter.
It's still incomplete. For production environment, we need to do more, e.g. methods and properties like contains, size, etc.
If you initialize the first level of the hash with objects, then you can reference the second level without typeErrors, even if the data was not defined before.
Example:
var _2dhash = {a: {}, b: {}, c:{}}
//Note you cannot start variable names with numbers in js
_2dhash['a']['missingElement'];
// > undefined
It works because you're accessing undefined properties of defined objects. If you try to access through a missing top-level object, ie.
_2dhash['d']['whatever'];
You will get a TypeError, because _2dhash.d was not defined, and the second lookup fails, trying to read the 'whatever' property of undefined.

Create a "Dictionary" in javascript

In C# I have a Model with 2 properties and a Dictionary with a String key:
public class Model
{
public string Route { get; set; }
public string Template { get; set; }
}
Dictionary<String, Model> models;
The key is the model name and model is an instance of class model.
I need to create a similar structure in Javascript where I could Get an item from the "Dictionary" given a key or find if there is an item with a specific key in the "Dictionary".
Is something in Javascript that could replicate this?
You could create a function that would represent the random item in your dictionary:
function Model(route, template)
{
this.route = route;
this.template = template;
}
Then you could create an object like below:
var dictionary = {
"key1": new Model("route1", "template1"),
"key2": new Model("route2", "template2")
};
In JavaScript objects are containers for key/value pairs.
How we get the value for a specific key?
var model = dictionary["key1"];
or
var model = dictionary.key1;
If key1 isn't a key of dictionary, then you will get as model the undefined.
How we set the value for a specific key?
dictionary.key5 = new Model("route5", "template5");
What happens if there is already the key5 ?
You just assign a new value for this key. As it would happen, if we were in c#.
Above we used the constructor pattern, in order we create the values of our dictionary. This is a commonly used pattern for the creation of objects with the same properties.
In Javascript, a dictionary with string keys is just a plain object:
var models = {};
Add an element:
model.myKey = 'my value';
Get an element:
var value = model.myKey;
Check that an element exists:
if (model.myKey) { ...
(note that this will yield false for any Javascript falsey value, so if you store things like 0 or '' you should use the more pedantically correct method model.hasOwnProperty('myKey'))
Remove an element:
delete model.myKey;
You can also add elements when creating the object:
var obj = {
'an item': 1,
anotherItem: 'another value'
};
Note that keys can be accessed with a dot notation if they're valid Javascript identifiers:
var value = obj.key;
Or as values in brackets (useful if they're not valid identifiers or if you want to use a variable):
var value = obj['A key'];
var fromVar = obj[someVariableHoldingAKeyName];
(JSHint even has a rule that checks for that)
As for your model class, it could similarly be modeled as an object with keys 'route' and 'template', e.g:
var myModel = { route: 'my route', template: 'my template' };
The next version of ECMAScript introduces Map, which allows to use a value of any data type as key. Map is already supported in a variety of browsers.
Example:
var map = new Map();
map.set('foo', data);
map.get('foo);
As already mentioned, objects are also often used as dictionaries, and sufficient in most cases. However, some care has to be taken:
The default prototype of objects is Object.prototype, so they already contain some "default" entries (like toString or hasOwnProperty). This can be avoided by explicitly creating an object with no prototype: var dict = Object.create(null);
Similar to above, because Object.prototype can be extended, your "dictionary" could be changed as well without you knowing it. Object.create(null) solves that problem as well.
Similar to the other answers. You're probably well off to put your model into an Array (however you're getting them), and then looping through that array to create your dictionary object.
var models = {};
var m1 = {name:'Joe',age:25};
var m2 = {name:'Bill',age:30};
var m3 = {name:'Andy',age:50};
var arr = [m1,m2,m3];
for(var m in arr){
models[arr[m].name] = arr[m];
}
//console.log(models);
var joe = models.Joe;
var joe = models['Joe'];

Categories

Resources