Typescript class array assign by value - arrays

How to assign typescript class object array by value not by reference.
Below is the code
class Person {
constructor(public Name: string, public Age: number) {
}
}
let orignalArr: Person[] = [
new Person('Gyan', 28),
new Person('Parkash', 28),
];
let arr2 = orignalArr;
//let arr2 = orignalArr.slice(0); i tried this but not working
arr2[0].Name = 'changed';
console.log(orignalArr);
//logs 0: Person {Name: "changed", Age: 28} 1: Person {Name: "Parkash", Age:
// 28}
console.log(arr2);
//logs 0: Person {Name: "changed", Age: 28} 1: Person {Name: "Parkash", Age:
// 28}
So what i need is the value of original array should not be changed.

slice will not work, because your items are also reference type and it will just return the copies of the references.
You can use map function to iterate over array items and then using Object.assign, you can copy the properties of each object into the new object.
The example is provided in Javascript.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let originalArr = [
new Person('Gyan', 28),
new Person('Parkash', 28),
];
let arr2 = originalArr.map(item => Object.assign({}, item));
arr2[0].name = 'Changed';
console.log(originalArr[0]);
console.log(arr2[0]);

Related

I'm trying to understand reduce and i'm scratching my head about this, why is this code not giving the expected result

I am reduce an array of object into a single object that should look like this :
`
result = {
23 : [{obj of kyle}, {obj of jade}],
29 : [{obj of ruby}]
32 : [{obj of mat}]
}
`
I have used reduce to do this, each person variable will refer to an object of the array to reduce, and they all collapse into a single object refered to with the variable group, the initial value of that object is an empty object {}, so with an if statement i checked first if it's empty, then create a key named age with a new empty array as value and push the person object into that empty array, and if the key age exists, then skip the new array creation and push that corresponding person object into the corresponding array.
what's wrong with this code?
`
const people = [
{name: "kyle", age: 23},
{name: "jade", age: 23},
{name: "ruby", age: 29},
{name: "mat", age: 32}
]
let result = people.reduce(function(person, group){
const age = person.age;
if(group[age]==null){
group[age] = []
}
group[age].push(person);
return group
},{})
console.log(result);
`
not what i expected
Looking again at your code it seems that you can fix your own code by replacing person and group in your callback function inside reduce like so
const people = [
{name: "kyle", age: 23},
{name: "jade", age: 23},
{name: "ruby", age: 29},
{name: "mat", age: 32}
]
let result = people.reduce(function(group, person){
const age = person.age;
if(group[age]==null){
group[age] = []
}
group[age].push(person);
return group
},{})
console.log(result);
You can do something like this as well
const people = [
{name: "kyle", age: 23},
{name: "jade", age: 23},
{name: "ruby", age: 29},
{name: "mat", age: 32}
];
const result = people.reduce((acc, curr) => {
if (!acc[curr.age]) {
return {...acc, [curr.age]: [curr]}
}
return {...acc, [curr.age]: [...acc[curr.age], curr]};
}, {});
console.log(result);
What we did here is initiating it with a new object like you did, then for each element in the array denoted as curr for current we check if our new object (denoted as acc for accumulator) has a key with this age already of curr.age. If not we make an array for this age and put the current element inside.
Else, if this age key already exist just add to that age array the current element.

Array of instances: Transform one specific value, in each instance, return a new array

struct Person {
var name: String
var age: Int
var weight : Int
var shoeSize: Int
}
struct Group {
var members : [Person]
}
let mygroup = Group(members: [
Person(name: "Billy", age: 59, weight: 170, shoeSize: 9),
Person(name: "Jacob", age: 19, weight: 130, shoeSize: 11),
Person(name: "Zara", age: 25, weight: 320, shoeSize: 10)
])
How can I multiple each age by 2, and return a new array (myGroupV2), but leave the other elements untouched?
You simply need to use map to apply a closure to each element of an Array. In your map closure, you need to initialise a new Person instance, where all inputs are the same as the properties of the original Person, except for age, which you multiply by 2.
let myGroup2 = Group(members: mygroup.members.map { Person(name: $0.name, age: $0.age * 2, weight: $0.weight, shoeSize: $0.shoeSize) })
Instead of individually assigning all the properties of Person, you can simply create a new Person instance and change its age property, i.e.
let myGroupV2 = mygroup.members.map {(person) -> Person in
var person = person
person.age *= 2
return person
}
In case you need it more than once, an extention can also be helpful:
extension Person {
var asDoubleAged: Person {
get {
return Person(name: self.name, age: self.age * 2, weight: self.weight, shoeSize: self.shoeSize)
}
}
}
let myGroupV2 = Group(members: mygroup.members.map { $0.asDoubleAged })
let personArray = mygroup.members.map { p in Person(name: p.name, age: p.age*2, weight: p.weight, shoeSize: p.shoeSize) }
let mygroup2=Group(members: personArray)
or
let mygroup2 = Group(members: mygroup.members.map { Person(name: $0.name, age: $0.age*2, weight: $0.weight, shoeSize: $0.shoeSize)})

Swift - Check if a value belongs is in an array

I have an array of type "User" and I would like to check if a value belongs to a property type.
My code :
struct User: Identifiable {
var id = UUID()
var name: String
var age: String
}
var array: User = [
User[name: "AZE", age: "10"]
User[name: "QSD", age: "37"]
]
For example I'd like to know if "AZE" belongs to the property array "name". What is the function for retrieving this information. I hope you understood my problem and thank you for your answer.
First of all, arrays define with [Type] like [User]
Second of all init method calls as with (Arguments) like User(name: ,age:)
And last but not least, don't forget the ',' between elements of the array.
So
struct User: Identifiable {
var id = UUID()
var name: String
var age: String
}
var array: [User] = [
User(name: "AZE", age: "10"),
User(name: "QSD", age: "37")
]
So now you can check your element inside with contains like
array.contains(where: { user in user.name == "AZE" }) // returns `true` if it is
Tips
Try name arrays not array. Use plural names instead like users
To returtning the found one:
users.first(where: { user in user.name == "AZE" })
To summarizing it
users.first { $0.name == "AZE" }

How to update a specific property value of all elements in array using Swift

Let's say I already have an Array of ViewHolder which is viewHolderList: [ViewHolder].
I want all isMarried field of elements to "false" in a single line without looping.
struct ViewHolder {
var name: String?
var age: Int?
var isMarried: Bool = true
}
You just need to iterate your array indices using forEach method and use the array index to update its element property:
struct ViewHolder {
let name: String
let age: Int
var isMarried: Bool
}
var viewHolders: [ViewHolder] = [.init(name: "Steve Jobs", age: 56, isMarried: true),
.init(name: "Tim Cook", age: 59, isMarried: true)]
viewHolders.indices.forEach {
viewHolders[$0].isMarried = false
}
viewHolders // [{name "Steve Jobs", age 56, isMarried false}, {name "Tim Cook", age 59, isMarried false}]
You can also extend MutableCollection and create a mutating method to map a specific property of your collection elements as follow:
extension MutableCollection {
mutating func mapProperty<T>(_ keyPath: WritableKeyPath<Element, T>, _ value: T) {
indices.forEach { self[$0][keyPath: keyPath] = value }
}
}
Usage:
viewHolders.mapProperty(\.isMarried, false)
viewHolders // [{name "Steve Jobs", age 56, isMarried false}, {name "Tim Cook", age 59, isMarried false}]

How to mutate Values inside a Array

I need to mutate the following array:
struct Person {
var name: String
var age = 0
}
func showPersonArray() -> [Person] {
var dataArray = [Person]()
dataArray.append(Person(name: "Sarah_Yayvo", age: 29))
dataArray.append(Person(name: "Shanda_Lear", age: 45))
dataArray.append(Person(name: "Heidi_Clare", age: 45))
return dataArray
}
How could I split the "name"-key into two keys: "givenName" and "familyName".
Some nice person gave me this code before:
let arraySeparated1 = dataArray.map { $0.substring(to: $0.range(of: "_")!.lowerBound) }
let arraySeparated2 = dataArray.map { $0.substring(from: $0.range(of: "_")!.upperBound) }
Is it possible to make the mutation inside the struct?
The function showPersonArray() is only for demo and test.
Maybe there is a way to work with a target struct, like this:
struct Persontarget {
var familyname: String
var givenName: String
var age = 0
}
struct Person: Array -> [Persontarget] {
var name: String
var age = 0
// Here the split/mutating code
return [PersonWithTwoNames]
}
Or with an String extension. Possibly my question sounds pretty newby-like, but i´m trying the whole day...
Thanks everyone!
I would write an initializer on the new Person type, which initializes it from the old person type (which I called LegacyPerson):
import Foundation
struct LegacyPerson {
let name: String
let age: Int
}
func getPersonArray() -> [LegacyPerson] {
return [
LegacyPerson(name: "Sarah_Yayvo", age: 29),
LegacyPerson(name: "Shanda_Lear", age: 45),
LegacyPerson(name: "Heidi_Clare", age: 45)
]
}
struct Person {
let familyName: String
let givenName: String
let age: Int
}
extension Person {
init(fromLegacyPerson person: LegacyPerson) {
let index = person.name.range(of: "_")!
self.init(
familyName: person.name.substring(from: index.upperBound),
givenName: person.name.substring(to: index.lowerBound),
age: person.age
)
}
}
let people: [Person] = getPersonArray().map(Person.init)
people.forEach{ print($0) }
Create a method or computer variable for your Person class that returns what you want.
func firstName() -> String {
return self.substring(to: $0.range(of: "_")!.lowerBound)
}
You should not force cast though
with help of computed property defined in an extension
struct Person {
let name: String
let age: Int
}
let person = Person(name: "Maria_Terezia", age: 300)
extension Person {
var names:[String] {
get {
return name.characters.split(separator: "_").map(String.init)
}
}
}
for name in person.names {
print(name)
}
prints
Maria
Terezia

Resources