iOS Swift access string in array - ios

I set up an array like this:
let modelArray = [
"Casual": ["health": 17, "weapon": 8, "crafting": 15, "social": 30],
"Soldier": ["health": 25, "weapon": 32, "crafting": 8, "social": 5],
"Doctor": ["health": 35, "weapon": 5, "crafting": 15, "social": 15],
"Dorothy": ["health": 15, "weapon": 15, "crafting": 20, "social": 20],
"Asian": ["health": 13, "weapon": 5, "crafting": 7, "social": 45],
"Police": ["health": 23, "weapon": 22, "crafting": 5, "social": 20]
]
How do I access the String (for example "Casual") value when looping?
for (index, model) in character.modelArray.enumerate()
{
print("\(index) carries: \(model[0]")
}
This gives me Type '(String, Dictionary)' has no subscript members

As Josh points out, your modelArray object is a dictionary of dictionaries. (let modelArray : [String: [String:Int]] is the full type information).
The dictionary within can't be subscripted using an Int, only a String.
Here's a version of your code, which will get some the health stat of each character:
for statDictionary in characters.modelArray {
let health = statDictionary["health"]
print(health)
}
further suggestion
Storing data like this in a dictionary is fine for some purposes, but you may find a cleaner, safer API can be made by creating structs (or classes) for holding this state information.
struct CharacterStats {
let health : Int
let weaponNumber : Int
// etc.
}
Then enumerating would be even simpler and require no loose string keys (which could be mistyped).
for stat in characters {
let health = stat.health
}

Just my point of view.
A dictionary of dictionaries is ugly
Create a model type
struct Model {
let name: String
let health: Int
let weapon: Int
let crafting: Int
let social: Int
}
and then your array
let models = [
Model(name: "Casual", health: 17, weapon: 8, crafting: 15, social: 30),
Model(name: "Soldier", health: 25, weapon: 32, crafting: 8, social: 5),
Model(name: "Doctor", health: 35, weapon: 5, crafting: 15, social: 15),
Model(name: "Dorothy", health: 15, weapon: 15, crafting: 20, social: 20),
Model(name: "Asian", health: 13, weapon: 5, crafting: 7, social: 45),
Model(name: "Police", health: 23, weapon: 22, crafting: 5, social: 20),
]
Looping
Now you can simply
for model in models {
print(model.name)
}
Update: Searching
if let doctor = models.filter({ $0.name == "Doctor" }).first {
print(doctor.health)
}

Related

How to set literals after Dart 2.2

Set literals were not supported until 2.2, How to set literals after Dart 2.2. Please feel free to comment. Thank you.
class item_t {
String name;
int weight;
int value;
}
main() {
const List<item_t> items = [
{'map', 9, 1}, // reports errors
];
}
update 1
I could define the list as a serial of define statements. However, it seems it is ineffective.
class item_t {
String name;
int weight;
int value;
}
main() {
// final item_t items = new item_t(100);
List<item_t> items = new List(2);
items[0].name = 'map';
items[0].weight = 9;
items[0].value = 1;
}
In C language, I can define a structure effectively but I don't know how to do that in dart.
typedef struct {
char *name;
int weight;
int value;
} item_t;
item_t items[] = {
{"map", 9, 150},
{"compass", 13, 35},
{"water", 153, 200},
};
update 2
Thank you jamesdlin's advise, I can simplify the list initialization and access the element by index. However, it still can't be as effective as C language.
var mySet = [
{"map", 9, 150},
{"compass", 13, 35},
{"water", 153, 200},
{"sandwich", 50, 160},
{"glucose", 15, 60},
{"tin", 68, 45},
{"banana", 27, 60},
{"apple", 39, 40},
{"cheese", 23, 30},
{"beer", 52, 10},
{"suntan cream", 11, 70},
{"camera", 32, 30},
{"T-shirt", 24, 15},
{"trousers", 48, 10},
{"umbrella", 73, 40},
{"waterproof trousers", 42, 70},
{"waterproof overclothes", 43, 75},
{"note-case", 22, 80},
{"sunglasses", 7, 20},
{"towel", 18, 12},
{"socks", 4, 50},
{"book", 30, 10}
];
print(mySet[0].elementAt(1));
You use { and } to specify Set (and Map) literals:
var mySet = {1, 2, 3};
Note that to avoid ambiguity with Map literals, you must explicitly specify a type when creating an empty set. For example:
var emptySet = <int>{};
Also see https://dart.dev/guides/language/language-tour#sets
Just replace { and } with [ and ], respectively, and everything will work fine.

How to filter array of timestamp in order to keep specific hours?

Imagine this array of timestamps [Double] :
hourlyTimes": [1551344400, 1551348000, 1551351600, 1551355200, 1551358800, 1551362400, 1551366000, 1551369600, 1551373200 ... ]
It corresponds to the hours for which I have data to display.
To keep it simple, here is the full array when I display only the hours (UTC) :
Hours = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 3, 6, 9, 12, 15, 18, 21, 0, 3, 6, 9, 12, 15, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 12, 18, 0]
Now here is what I want to achieve, I need to filter this array of timestamp, in order to only keep these specific hours on any day (three-hourly).
[0, 3, 6, 9, 12, 15, 18, 21]
Ok, now let's have a look at the code :
let arrayOfTimestamp = time.hourlyTimes
let arrayOfHours = arrayOfTimestamp.map({ Date.init(timeIntervalSince1970: $0).hoursUTC})
let hoursToKeep = [0, 3, 6, 9, 12, 15, 18, 21]
let filtered = arrayOfHours.intersection(with: hoursToKeep)
Some explanations here:
time in the first line is the response from the backend, returning me all the available timestamps.
struct MultiForecastTimeModel: Codable {
let hourlyTimes: [Double]
let dailyTimes: [Double]
}
.hoursUTC is just a Date extension, in order to retrieve the hour component of the Date object.
var hoursUTC: Int {
var calendar = Calendar.current
let timezone = TimeZone(abbreviation: "UTC")!
calendar.timeZone = timezone
return calendar.component(.hour, from: self)
}
And finally, .intersection is an extension too, in order to do the same as a classic intersection, but also keeping the index and the occurrences.
extension Collection where Element: Equatable {
func intersection(with filter: [Element]) -> [Element] {
return self.filter { element in filter.contains(element) }
}
}
Everything is working fine, my only issue is that I now have to associate all these values as an Array of tuples.
Like this :
let tuples = Array(zip(filtered, filtered.dropFirst()))
But with an actual timestamp (corresponding to real date), not just an array of Int (hour component).
Because in the end, here what I have to do :
self.hourlyMapDataSource.data.value = tuples
and my datasource is expecting a tuple of timestamp (Double, Double)
class HourlyMapDataSource : GenericDataSource<(Double, Double)>, UICollectionViewDataSource { }
Do you have any pieces of advice on how should I improve my code and/or my logic?
Thank you in advance.
EDIT: My tuple array should only contain timestamps whose time has been "validated" through the hoursToKeep array so that it has 3 hours difference between hours.
I will show you with the hours to keep it simple, but it's an actual corresponding timestamp that I want :
[(9, 12), (12, 15), (15, 18) ...]
var tupleArray = hourlyTimes.map { (time: $0, hour: Date.init(timeIntervalSince1970: $0).hoursUTC)}
Now you can run the reduce function on this
var selectedHours = tupleArray.filter { return hoursToKeep.contains($0.hour) }
This will give you an array of tuples which have the validated hours,
[(1551344400, 9), (1551348000, 12)]

Cut elements of array in Swift 2

I have array of elements (it's a basic array). Type of array is String
basicArray = [1710, 1725, 1740, 1755, 1810, 1825, 1840, 1855, 1925, 1955, 2020, 2050, 2120, 2150, 2220, 2250, 2320, 2350, 2430]
I need to create two new arrays where each element of basicArray must be cut into two parts, for example:
array1 = [17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 20, 20....]
array2 = [10, 25, 40, 55, 10, 25, 40, 55, 25,55, 20, 50...]
How better to do it? Thank you for your advice!
let basic = ["1710", "1725", "1740", "1755", "1810", "1825", "1840", "1855", "1925", "1955", "2020", "2050", "2120", "2150", "2220", "2250", "2320", "2350", "2430"]
let array1 = basic.map { String($0.characters.prefix(2)) }
let array2 = basic.map { String($0.characters.suffix(2)) }
print(array1)
print(array2)
Output:
["17", "17", "17", "17", "18", "18", "18", "18", "19", "19", "20", "20", "21", "21", "22", "22", "23", "23", "24"]
["10", "25", "40", "55", "10", "25", "40", "55", "25", "55", "20", "50", "20", "50", "20", "50", "20", "50", "30"]
Something like this?
Try this (Hints are in the code comments):
var basicArray = [1710, 1725, 1740, 1755, 1810, 1825, 1840, 1855, 1925, 1955, 2020, 2050, 2120, 2150, 2220, 2250, 2320, 2350, 2430]
var firstTwoDigitsArray = [Int]()
var lastTwoDigitsArray = [Int]()
for element in basicArray {
// dividing by 100 shifts the numbers down by the first two digits
firstTwoDigitsArray.append(element/100)
// modulo 100 gets the last two digits
lastTwoDigitsArray.append(element%100)
}
print(firstTwoDigitsArray) // [17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24]
print(lastTwoDigitsArray) // [10, 25, 40, 55, 10, 25, 40, 55, 25, 55, 20, 50, 20, 50, 20, 50, 20, 50, 30]
Swift has a built in method called filter which basically is a closure that iterates over all elements and lets you -- as the name suggests -- filter the elements based on a predicate:
let array = [1,2,3,4,5,6]
let array1 = array.filter { $0 % 2 == 0 }
print(array1) // [2, 4, 6]
let array2 = array.filter { $0 % 2 == 1 }
print(array2) // [1,3,5]
You haven't made clear how you want those arrays to be filtered, so it's hard to explicitly give the answer that you might be looking for...

The Swift Programming Language Book Chapter Section on Control Flow Experiment 3

I am working through the first chapter of the book and can't figure out the experiment:
Add another variable to keep track of which kind of number was the
largest, as well as what that largest number was.
This is the code from the book:
let interstingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13, 17],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25, 36],
]
var largest = 0
for (kind, numbers) in interstingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
largest
Like this:
let interstingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13, 17],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25, 36],
]
var largest = 0
var largestKind = ""
for (kind, numbers) in interstingNumbers {
for number in numbers {
if number > largest {
largest = number
largestKind = kind
}
}
}
largest
largestKind
So basically you'd want to put kind somewhere at the same time as you put number into largest, e.g. into a variable called largestKind.
The question asked to keep track of the value and type not to just display the type of the final answer.
I think this gets closer:
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var largestType = [String]()
var largestValues = [Int]()
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
largestValues.append(largest)
largestType.append(kind)
}
}
}
print(largest)
print(largestType)
print(largestValues)
And now with tuples:
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var largestValues: [(type: String, value: Int)] = []
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
largestValues.append(type: kind, value: number)
}
}
}
print(largest)
print(largestValues)
let interestingNumbers = [ "Prime" : [2,3,5,7,11,13],
"Fibonacci" : [1,1,2,3,5,8,13],
"Square" : [1,4,9,16,25,36],
]
var largest = 0
var largestKind = ""
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
largestKind = kind
}
}
}
print(largest, largestKind)
outputs : 36 Sqaure
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var largestNumbers = [
"Prime":0,
"Fibonacci":0,
"Square":0,
]
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
if(number > largestNumbers[kind]!){
largestNumbers[kind] = number;
}
}
}
print(largest)
print(largestNumbers)
Result is:
25
["Fibonacci": 8, "Square": 25, "Prime": 13]

Issue with Propel Criteria::IN

I'm trying as add following condition in my query
AND momento_distribution.MOMENTO_IDMEMBER IN ( 5, 1, 3, 10, 11, 12, 18, 32, 51, 6 )
For that, I'm having following code
$friendCsv=Friend::getFriendIdAsCsv($member); //returning string 5, 1, 3, 10, 11, 12, 18, 32, 51, 6
//code
$c->add(MomentoDistributionPeer::MOMENTO_IDMEMBER, $friendCsv, Criteria::IN);
Query is failing because it is generating
AND momento_distribution.MOMENTO_IDMEMBER IN ( '5, 1, 3, 10, 11, 12, 18, 32, 51, 6' )
Adding a single quote on string. If I remove that single quote manually, query runs successfully.
IS there any way to force propel not to put single quotes in values?
try that
$friendCsv=Friend::getFriendIdAsCsv($member); //returning string 5, 1, 3, 10, 11, 12, 18, 32, 51, 6
$friendArr= explode(',', $friendCsv);
//code
$c->add(MomentoDistributionPeer::MOMENTO_IDMEMBER, $friendArr, Criteria::IN);
Criteria::IN should be used with array not CSV.

Resources