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
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.
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)]
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...
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]
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.