The code below is creating a new map called nameTable, then adding an entry named example to it, then trying to print the name property of the Value.
When I run it, it seems that the plus operation didn't add a new entry to the map like I thought it would.
So what am I doing wrong?
class Person(name1: String, lastName1: String, age1: Int){
var name: String = name1
var lastName: String = lastName1
var age: Int = age1
}
var nameTable: MutableMap<String, Person> = mutableMapOf()
var example = Person("Josh", "Cohen", 24)
fun main (args: Array<String>){
nameTable.plus(Pair("person1", example))
for(entry in nameTable){
println(entry.value.age)
}
}
While we're at it, I would love some examples of how to add, remove, and get an entry from a map.
The reason for your confusion is that plus is not a mutating operator, meaning that it works on (read-only) Map, but does not change the instance itself. This is the signature:
operator fun <K, V> Map<out K, V>.plus(pair: Pair<K, V>): Map<K, V>
What you want is a mutating operator set, defined on MutableMap:
operator fun <K, V> MutableMap<K, V>.set(key: K, value: V)
So your code may be rewritten (with some additional enhancements):
class Person(var name: String, var lastName: String, var age: Int)
val nameTable = mutableMapOf<String, Person>()
val example = Person("Josh", "Cohen", 24)
fun main (args: Array<String>) {
nameTable["person1"] = example
for((key, value) in nameTable){
println(value.age)
}
}
The plus-method on Map creates a new map that contains the new entry. It does not mutate the original map. If you want to use this method, you would need to do this:
fun main() {
val table = nameTable.plus(Pair("person1", example))
for (entry in table) {
println(entry.value.age)
}
}
If you want to add the entry to the original map, you need to use the put method like in Java.
This would work:
fun main() {
nameTable.put("person1", example)
for (entry in nameTable) {
println(entry.value.age)
}
}
To get and remove entries from the MutableMap, you can use this:
nameTable["person1"] // Syntactic sugar for nameTable.get("person1")
nameTable.remove("person1")
It's too much trouble,You can assign values directly,like this:
#Test
#Throws(Exception::class)
fun main(){
val map:MutableMap<String,Person> = mutableMapOf()
map["Josh"]= Person("Josh", "Cohen", 24)
map.forEach { t, u ->
println("map key:$t,map value:${u.toString()}")
}
}
class Person(name1:String, lastName1:String, age1:Int){
var name:String = name1
var lastName:String = lastName1
var age:Int = age1
override fun toString(): String {
return "name:$name,lastNam:$lastName,age:$age \n"
}
}
You have to use
put
method.
class Person(name1:String, lastName1:String, age1:Int){
var name:String = name1
var lastName:String = lastName1
var age:Int = age1
}
var nameTable:MutableMap<String, Person> = mutableMapOf()
var example = Person("Josh", "Cohen", 24)
fun main (args: Array<String>){
nameTable.put("person1", example)
for(entry in nameTable){
println(entry.value.age)
}
}
val params: MutableMap<String, String> = HashMap<String, String>()
params.put("1", "A")
params.put("2", "B")
Related
I have a text file with three lines of code and need to take each line and split it by "," so I can take the pieces from each line and place them into a class. I'll have one class for each line.
This is what I have come up with sofar. I just think it's too much code and would like to find a simple way to do this.
The text file looks like this
character, stats, stats, stats
weapon, stats
armor, stats
my code for the first line looks like this
class CharacterFight(
var name : String,
var race : String,
var hitpoints :Int,
var strength : Int,
var agility : Int,
){
override fun toString(): String {
return """Character
Name: ${name}
Race: ${race}
Hitpoints :${hitpoints}
Strength: ${strength}
Agility: ${agility}
""".trimMargin()
}
}
var charactersStats = mutableListOf<CharacterFight>()
var charStats = mutableListOf<String>()
val fileName: String = "src/main/kotlin/gimli.txt"
var characterInfo = mutableListOf<String>()
var lines = File(fileName).readLines()
for (line in lines){
val pieces = line.split("\n")
characterInfo.add(line)
}
charStats.add(characterInfo[0])
for (stat in charStats){
var statpieces = stat.split(",")
var charpieces = CharacterFight(statpieces[0],statpieces[1],statpieces[2].toInt(),statpieces[3].toInt(),statpieces[4].toInt)
charactersStats.add(charpieces)
}```
To avoid boilerplate toString() code consider using data classes:
data class CharacterFight(var name: String, var race: String, var hitpoints: Int, var strength: Int, var agility: Int)
Assuming that other two classes are
data class Weapon(val name: String, val value: Int)
data class Armor(val name: String, val value: Int)
CSV deserializing could be done in the following manner (usage of destructuring declarations makes code more readable, but explicit toInt() convertion on a certain passing arguments still can't be avoided):
fun deserializeCSV(fileName: String): Triple<CharacterFight, Weapon, Armor> {
val (characterInfo, weaponInfo, armorInfo) = File(fileName).readLines().map { it.split(",") }
val character = run { //create separate scope to avoid clash of name variables
val (name, race, hitpointsStr, strengthStr, agilityStr) = characterInfo
CharacterFight(name, race, hitpointsStr.toInt(), strengthStr.toInt(), agilityStr.toInt())
}
val weapon = run { //create separate scope to avoid clash of name variables
val (name, valueStr) = weaponInfo
Weapon(name, valueStr.toInt())
}
val armor = run { //create separate scope to avoid clash of name variables
val (name, valueStr) = armorInfo
Armor(name, valueStr.toInt())
}
return Triple(character, weapon, armor)
}
If provided CSV format is not a hard requirment, I would recomend to use JSON instead:
{"name":"Gimli","race":"dwarf","hitpoints":90,"strength":40,"agility":3}
{"name":"Axe","value":25}
{"name":"Plate male","value":85}
Then with help of kotlinx.serialization library deserialization is fairly easy:
//don't forget to add `#Serializable` annotation to all deserializable classes
fun deserializeJSON(fileName: String): Triple<CharacterFight, Weapon, Armor> {
val (characterInfo, weaponInfo, armorInfo) = File(fileName).readLines()
val character: CharacterFight = Json.decodeFromString(characterInfo)
val weapon: Weapon = Json.decodeFromString(weaponInfo)
val armor: Armor = Json.decodeFromString(armorInfo)
return Triple(character, weapon, armor)
}
Edit: The problem is already solved by #vacawama. But if you are looking for an answer for NSObject classes, you should implement isEqual function which is NSObjectProtocol. Otherwise you gonna get an error says: " Redundant conformance of 'classname' to protocol 'Equatable' "
You can check this for details: Swift 2.2, Contains Method not working
In swift, how can i check if an object is in array?
I have a simple class like this;
class Test: {
private var _number: Int!
private var _type: String!
var number: Int {
return _number
}
var type: String {
return _type
}
init (number: Int, type: String) {
self._number = number
self._type = type
}
}
Also i have this class;
class TestRandom {
private let _numberArr: [Int] = [1,2,3,4,5,6,7,8,9,10]
private let _typeArr: [String] = ["x","y","z"]
public private(set) var _testArr: [Test] = []
private var _randomTest: Test!
func randomTestPicker () {
repeat {
let randomNumber = Int(arc4random_uniform(UInt32(self._numberArr.count)))
let randomType = Int(arc4random_uniform(UInt32(self._typeArr.count)))
self._randomTest = Test(number: self._numberArr[randomNumber], type: self._typeArr[randomType])
} while self._testArr.contains(_randomTest)
}
}
All i want to do is to pick different objects. Lets say i have x2,y4,x6,z3,z8,y2 in _testArr. When i call randomTestPicker, it should not pick x2 or z8. Because they are already in array.
I have tried contains as you see. However it did not work for me. Is there any solution that i can use for this purpose? Or what is the best way to do this?
Edit: I tried self._testArr.contains{$0 === _randomTest} but not working neither.
You can't use contains that way since your class doesn't conform to the Equatable protocol.
Add :Equatable to your class definition and implement the == function which compares two of your objects:
class Test: Equatable {
private var _number: Int!
private var _type: String!
var number: Int {
return _number
}
var type: String {
return _type
}
init (number: Int, type: String) {
self._number = number
self._type = type
}
}
func ==(lhs: Test, rhs: Test) -> Bool {
return lhs.number == rhs.number && lhs.type == rhs.type
}
The other way this could have been done is to use the predicate form of contains. The predicate takes two objects and returns a Bool indicating if they match. In that case, you would write:
self._testArr.contains { $0.number == _randomTest.number && $0.type == _randomTest.type }
As you can see, in this case the closure is essentially the == function from above, so implementing the Equatable protocol is the cleaner way to do it.
The closure { $0 === _randomTest } doesn't work because that only tests if the objects are the same instance. In your case, you need to check if the two objects have the same properties, and you are not interested if they are same instance. The way you are creating the objects, you never would create an instance that is already in the array, so this check would always return false.
How can I auto add a new class instance to an array?
Example:
class Product {
var name: String?
}
var products = [Product]()
How can I add a new instance of a Product class to the products Array? How can I append to the array?
I tried some code but I don't know how to reference the class in own class.
I tried something like this:
class Product {
var name: String?
init() {
products.append(Produt)
}
var products = [Product]()
Thanks!
If you want your newly created object stored in products array then you need to declare it as static property so that it is shared by all instance otherwise it will just add first object for your every instance.
class Product {
var name: String?
static var products = [Product]()
init() {
Product.products.append(self)
}
init(name: String) {
self.name = name
Product.products.append(self)
}
}
Now use this products array using Product.products.
_ = Product(name: "One")
_ = Product(name: "two")
print(Product.products)
I dont't know why you need it, but you can use
class Product {
static var products: [Product] = []
var name: String?
init() {
products.append(self)
}
}
Have you tried products.append(self) ?
I have spent hours trying to find a solution but can't find any. Apologies - novice here.
I want to add addCrewMember function in RocketShip class that will allow me to add new members to the crewMembers array.
I know that I should use append method but it keeps giving me error. Thoughts?
class RocketShip
{
var speed: Double
let modelNumber: Int
let shipName : String
var crewMembers: Array<String>
init (name: String, number: Int)
{
shipName = name
modelNumber = number
speed = 0.0
crewMembers = ["John", "Jane"]
}
func addSpeed(addedSpeed: Double)-> Double
{
speed = speed + addedSpeed
return speed
}
func addBoostedSpeed(addedSpeed: Double, numberOfBoosts: Int) -> Double
{
let boostedSpeed = addedSpeed * Double (numberOfBoosts)
speed = speed + boostedSpeed
return speed
}
func addCrewMembers(addCrewMembers: String) -> STring
{
addCrewMembers = crewMembers.append()
return crewMembers
}
}
You probably mean
func addCrewMembers(newMember: String) -> [String]
{
crewMembers.append(newMember)
return crewMembers
}
I have the below class and I use a function math to search the string in both SongTitle and in ESongTitle.
class KeerthanaiArray: NSObject {
var SongTitle: String = String()
var SongLyrics: String = String()
var ESongTitle: String = String()
init(SongTitle: String, SongLyrics:String, ESongTitle: String) {
self.SongTitle = SongTitle
self.SongLyrics = SongLyrics
self.ESongTitle = ESongTitle
}
class func match(string:String) -> Bool {
return SongTitle.containsString(string) || ESongTitle.containsString(string)
}
}
I get the error message 'Instance member SongTitle cannot be used on type 'Keerthanaiarray'. Please help
I need to declare the math func as class as I need to use the math function outside of its class
There are several problems here.
This class KeerthanaiArray is not an array (as suggested by the name instead)
Why are you extending NSObject?
The class method match makes no sense, it is using 2 properties (SongTitle and ESongTitle) that does not exists in this context because they belongs to an instance of the class.
So let's cleanup your code
struct Song {
let title: String
let lyrics: String
let eTitle: String
func match(keyword: String) -> Bool {
return title.containsString(keyword) || eTitle.containsString(keyword)
}
}
I make you class a struct because makes more sense. You are free to turn back to class. If you stay on structs please keep in mind they are value types.
Now given a list of Song(s)
let songs: [Song] = ...
and a keyword
let keyword = "The Great Gig In the Sky"
this is how we search the array
let results = songs.filter { $0.match(keyword) }
Case insensitive version
struct Song {
let title: String
let lyrics: String
let eTitle: String
func match(keyword: String) -> Bool {
let lowerCaseKeyword = keyword.lowercaseString
return title.lowercaseString.containsString(lowerCaseKeyword) || eTitle.lowercaseString.containsString(lowerCaseKeyword)
}
}