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...
Related
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)]
This question already has answers here:
In Swift, what's the cleanest way to get the last two items in an Array?
(9 answers)
Closed 5 years ago.
I need to get last 10 elements or min of 10 and array.count. In objective-C I have done it like this :
Objective-C code :
NSRange endRange = NSMakeRange(sortedArray.count >= 10 ? sortedArray.count - 10 : 0, MIN(sortedArray.count, 10));
NSArray *lastElements= [sortedArray subarrayWithRange:endRange];
In Swift I have done this :
let endRange = NSMakeRange(values.count >= 10 ? values.count - 10 : 0, min(values.count , 10) )
But don't know how to get the array using this range in swift. Any help would be appreciated. Thanks.
You can use Array Instance Method suffix(_:). Note that using suffix you don't need to check your array count. It will take up to 10 elements from the end of your array.
let array = Array(1...100) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
let lastTenElements = Array(array.suffix(10)) // [91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
You can get it by declaring Range:
let letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n"]
let desiredRange = letters.index(letters.endIndex, offsetBy: -10) ..< letters.endIndex
// ["e", "f", "g", "h", "i", "j", "k", "l", "m", "n"]
let lastTenLetters = (desiredRange.count > letters.count) ? letters : Array(letters[desiredRange])
Note that if the desired range's count is more than the main array's count, the last ten elements should be the whole main array.
Although I still agree that Leo's answer is the proper one for your case, I would like to mention that the good thing about this solution is that it is applicable for not only last element, to make it clear, consider that you want to get 10 elements after the first one (referring to letters array, elements should be b-k), by implementing a desired range, you could achieve this, as follows:
let letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n"]
let desiredRange = letters.index(letters.startIndex, offsetBy: 1) ..< letters.index(letters.startIndex, offsetBy: 11)
// ["b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
let lastTenLetters = (desiredRange.count > letters.count) ? letters : Array(letters[desiredRange])
var values : NSArray = [1,2,3,4,5,6,7,8,9,10,11]
values = values.reversed() as NSArray
let tenDigits = values.prefix(10)
debugPrint(values.count >= 10 ? NSArray(array: (Array(tenDigits))) : min(values.count , 10))
I am new in programming and swift and I am trying to make a chart with 2 lines. And on top of the chart to enumerate the Array of Strings that I have (DD-MM in my case). I managed to draw just one line like so:
let testArrayTemp = [22.43, 14.86,20.63, 17.08,23.68,14.12,11.09,13.89, 15.0, 9.86, 7.71,10.0,11.94, 8.68, 8.91,6.81, 9.03,8.89, 9.7, 9.26, 9.43,10.22, 9.04,8.04, 7.56,10.44, 7.22, 13.67,9.44, 7.67, 5.99]
let testArrayFeel = [20.43, 13.86,10.63, 15.08,22.68,11.12,10.09,15.89, 13.0, 6.86, 5.71,11.0,10.94, 7.68, 6.91,5.81, 3.03,5.89, 7.7, 8.26, 8.43, 11.22, 6.04,7.04, 6.56,11.44, 6.22, 12.67,10.44, 5.67, 4.99]
let testDayArray = ["Oct 2, 2016", "Oct 3, 2016", "Oct 4, 2016", "Oct 5, 2016", "Oct 6, 2016", "Oct 7, 2016", "Oct 8, 2016", "Oct 9, 2016", "Oct 10, 2016", "Oct 11, 2016", "Oct 12, 2016", "Oct 13, 2016", "Oct 14, 2016", "Oct 15, 2016", "Oct 16, 2016", "Oct 17, 2016", "Oct 18, 2016", "Oct 19, 2016", "Oct 20, 2016", "Oct 21, 2016", "Oct 22, 2016", "Oct 23, 2016", "Oct 24, 2016", "Oct 25, 2016", "Oct 26, 2016", "Oct 27, 2016", "Oct 28, 2016", "Oct 29, 2016", "Oct 30, 2016", "Oct 31, 2016", "Nov 1, 2016"]
setChart(dataPoints: testDayArray, valuesTempChart: testArrayTemp, valuesFeelChart: testArrayFeel)
}
//MARK:- Set Chart
func setChart(dataPoints: [String], valuesTempChart: [Double], valuesFeelChart: [Double])
{
var tempEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count
{
let dataEntry = ChartDataEntry(x: Double(i), y: valuesTempChart[i])
tempEntries.append(dataEntry)
}
let lineChartDataSetTemp = LineChartDataSet(values: tempEntries, label: "Temperature")
lineChartDataSetTemp.setColor(UIColor.red)
// lineChartDataSetTemp.mode = .cubicBezier
lineChartDataSetTemp.drawCirclesEnabled = true
lineChartDataSetTemp.lineWidth = 2.0
lineChartDataSetTemp.circleRadius = 5.0
lineChartDataSetTemp.highlightColor = UIColor.green
lineChartDataSetTemp.drawHorizontalHighlightIndicatorEnabled = true
var dataSets = [IChartDataSet]()
dataSets.append(lineChartDataSetTemp)
let lineChartDataTemp = LineChartData(dataSets: dataSets)
lineChart.data = lineChartDataTemp
lineChart.animate(xAxisDuration: 2.0, yAxisDuration: 2.0)
lineChart.noDataText = "There is no provided data from the server. Please check out later!"
}
but it looks like so:
what I need to do to show the String array on top (with the days) and to add one more line. please any idea, or maybe a link to a tutorial in SWIFT 3 not other version, cause they made a lot of changes, and nothing from swift 2 tutorials works as it should, but the autocorrection does even worse.
I would like it to look something like this: (but with 2 lines and days in stead of months)
Thank you for any suggestions
What you need to do is repeat the process for the feels data. Reference the code below.
func setChart(dataPoints: [String], valuesTempChart: [Double],valuesFeelChart: [Double])
{
var tempEntries: [ChartDataEntry] = []
var feelEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count
{
let dataEntryOne = ChartDataEntry(x: Double(i), y: valuesTempChart[i])
let dataEntryTwo = ChartDataEntry(x: Double(i), y: valuesFeelChart[i])
tempEntries.append(dataEntryOne)
feelEntries.append(dataEntryTwo)
}
let lineChartDataSetTemp = LineChartDataSet(values: tempEntries, label: "Temperature")
let lineChartDataSetFeels = LineChartDataSet(values: feelEntries, label: "Feels")
var dataSets = [IChartDataSet]()
dataSets.append(lineChartDataSetTemp)
dataSets.append(lineChartDataSetFeels)
let lineChartD = LineChartData(dataSets: dataSets)
lineChart.data = lineChartD
lineChart.animate(xAxisDuration: 2.0, yAxisDuration: 2.0)
lineChart.noDataText = "There is no provided data from the server. Please check out later!"
}
Hope this helps!
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)
}
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]