How to get the dates in an array in iOS swift? - swift

I have an array like:
["2018-03-21 11:09:25","2018-03-22 11:09:25","2018-03-23 11:09:25","2018-03-24 11:09:25"]
I need to display only dates [2018-03-21] in this array. How to split this array?

Considering you have and want Strings, here is a way you could use with Swift 4:
var myArray = [String]()
for date in dateArray {
myArray.append(date.split(" ")[0])
}

You have to split your task in subtasks to make it easy for you.
How to transform your data?
Given an your input 2018-03-21 11:09:25 and your ouput 2018-03-21, there are several ways.
I see 3 regular ways here (there are more of course):
Splitting with the space character as a delimiter and take the first part
Using a DateFormatter
Using substring to the 10th character
As 2. seems overkill and 3. would need to work with ranges (I'm lazy), let's take 1. as an example:
let ouput = input.split(" ")[0]
How to apply to the whole array?
You have many options, again, but the simpler is map.
Given your initial array is called array.
Solution
let result = array.map { $0.split(" ")[0] }

Related

How to print to more than 1 label using a for in loop

I'm trying to write my first app in swift on Xcode and I'm stuck!!
I have a dictionary - I've shuffled it - and now want to print the values to different labels in the order they have been shuffled in.
I'll give an example and try and explain the outcome I am expecting.
label1 : UILabel!
label2 : UILabel!
label3 : UILabel!
label4 : UILabel!
animals = [1:"cat", 2:"dog", 3:"snake", 4:"Mouse"]
shuffled animals = animals.Shuffled
// - expecting output like [2:"dog, 4:"mouse", 1:"cat", 3:"snake"
I tried...
`Label1.text =shuffledanimals[0] Label2.text = shuffledAnimals[1] Label3.text = shuffledAnimals[2] Label4.text = shuffledAnimals[3]'
// like the index of the dictionary.. (this didn't work) not sure why??
Also is there a way to put this in a loop to make it cleaner ?
Any help will be appreciated .. Thanks
Please note.. I would like to use a dictionary over an array as I have other needs for the keys.. and it has 40 pairs in so my method is not practical at all
In this example, you're using a dictionary, which is inherently unordered. So unlike arrays, where you can access information using indices like array[0] and array[1], dictionaries don't work the same way. No matter the order that you might be seeing the dictionary, whenever you access animals[1], it'll always be "cat" because that is "Cat"'s address in the dictionary.
There are a couple solutions for what you're trying to do. A quick and dirty way to do this is to create a second array (NOT a dictionary). Something like this:
let array : [Int] = [1,2,3,4]
Then, you can shuffle this array by doing something like:
array.shuffled()
Lastly, select a random dictionary piece by using the new (random) order of the array like this:
label1.text = animals[array[0]]
So long as you have the same numbers in array as you do as the first part of your animals dictionary, this will work just fine. But be careful to not accidentally add a number that isn't in animals, because that'll cause an error.
Alternatively, another solution is mentioned here that uses different and more advanced ways of declaring dictionaries:
Dictionary returns consecutive/shuffled values when iterating in swift
In terms of putting it into a loop, if you use the first option, you can do something like this:
for item in array {
print(animals[array(item)]
}
this will call each of the items in the array, which will have been shuffled provided you have already called the .shuffled() function.

Ordering of Dictionary Swift

I'm trying to work through a problem at the moment which is currently doing the rounds on the internet. The problem is: Given an array of characters, find the first non repeating character. I had a go at it and solved it but I was curious about how other people solved it so I did some looking around and found this answer:
let characters = ["P","Q","R","S","T","P","R","A","T","B","C","P","P","P","P","P","C","P","P","J"]
var counts: [String: Int] = [:]
for character in characters {
counts[character] = (counts[character] ?? 0) + 1
}
let nonRepeatingCharacters = characters.filter({counts[$0] == 1})
let firstNonRepeatingCharacter = nonRepeatingCharacters.first!
print(firstNonRepeatingCharacter) //"Q"
Source: Finding the first non-repeating character in a String using Swift
What I don't understand about this solution, is why it always returns Q, when there are other elements "S" "A" "B" and "J" that could be put first when the filter is applied to the dictionary. My understanding of dictionaries is that they are unordered, and when you make one they change from run to run. So if I make one:
let dictionary:[String:Int] = ["P": 9, "C": 8, "E": 1]
And then print 'dictionary', the ordering will be different. Given this, can anyone explain why the solution above works and maintains the order in which the dictionary elements were added?
You are not looking correctly at the code. The filter is not applied to a dictionary. It is applied to the array (characters), which has a defined order. The dictionary is used only to store counts.

Can this be more Swift3-like?

What I want to do is populate an Array (sequence) by appending in the elements of another Array (availableExercises), one by one. I want to do it one by one because the sequence has to hold a given number of items. The available exercises list is in nature finite, and I want to use its elements as many times as I want, as opposed to a multiple number of the available list total.
The current code included does exactly that and works. It is possible to just paste that in a Playground to see it at work.
My question is: Is there a better Swift3 way to achieve the same result? Although the code works, I'd like to not need the variable i. Swift3 allows for structured code like closures and I'm failing to see how I could use them better. It seems to me there would be a better structure for this which is just out of reach at the moment.
Here's the code:
import UIKit
let repTime = 20 //seconds
let restTime = 10 //seconds
let woDuration = 3 //minutes
let totalWOTime = woDuration * 60
let sessionTime = repTime + restTime
let totalSessions = totalWOTime / sessionTime
let availableExercises = ["push up","deep squat","burpee","HHSA plank"]
var sequence = [String]()
var i = 0
while sequence.count < totalSessions {
if i < availableExercises.count {
sequence.append(availableExercises[i])
i += 1
}
else { i = 0 }
}
sequence
You can overcome from i using modulo of sequence.count % availableExercises.count like this way.
var sequence = [String]()
while(sequence.count < totalSessions) {
let currentIndex = sequence.count % availableExercises.count
sequence.append(availableExercises[currentIndex])
}
print(sequence)
//["push up", "deep squat", "burpee", "HHSA plank", "push up", "deep squat"]
You can condense your logic by using map(_:) and the remainder operator %:
let sequence = (0..<totalSessions).map {
availableExercises[$0 % availableExercises.count]
}
map(_:) will iterate from 0 up to (but not including) totalSessions, and for each index, the corresponding element in availableExercises will be used in the result, with the remainder operator allowing you to 'wrap around' once you reach the end of availableExercises.
This also has the advantage of preallocating the resultant array (which map(_:) will do for you), preventing it from being needlessly re-allocated upon appending.
Personally, Nirav's solution is probably the best, but I can't help offering this solution, particularly because it demonstrates (pseudo-)infinite lazy sequences in Swift:
Array(
repeatElement(availableExercises, count: .max)
.joined()
.prefix(totalSessions))
If you just want to iterate over this, you of course don't need the Array(), you can leave the whole thing lazy. Wrapping it up in Array() just forces it to evaluate immediately ("strictly") and avoids the crazy BidirectionalSlice<FlattenBidirectionalCollection<Repeated<Array<String>>>> type.

Display certain number of letters

I have a word that is being displayed into a label. Could I program it, where it will only show the last 2 characters of the word, or the the first 3 only? How can I do this?
Swift's string APIs can be a little confusing. You get access to the characters of a string via its characters property, on which you can then use prefix() or suffix() to get the substring you want. That subset of characters needs to be converted back to a String:
let str = "Hello, world!"
// first three characters:
let prefixSubstring = String(str.characters.prefix(3))
// last two characters:
let suffixSubstring = String(str.characters.suffix(2))
I agree it is definitely confusing working with String indexing in Swift and they have changed a little bit from Swift 1 to 2 making googling a bit of a challenge but it can actually be quite simple once you get a hang of the methods. You basically need to make it into a two-step process:
1) Find the index you need
2) Advance from there
For example:
let sampleString = "HelloWorld"
let lastThreeindex = sampleString.endIndex.advancedBy(-3)
sampleString.substringFromIndex(lastThreeindex) //prints rld
let secondIndex = sampleString.startIndex.advancedBy(2)
sampleString.substringToIndex(secondIndex) //prints He

MatLab cells date format conversion

I have a lot of dates in MatLab (over 2 millions). Al these dates are in a cell array in 'yyyymmdd' format, and I want to convert them to 'yyyy-mm-dd' format and put this result in a cell array (not in a char matrix).
I know that I can use
temp = datestr(datenum(datesArray,'yyyymmdd'),'yyyy-mm-dd'),
and then use
mat2cell(temp, ones(1,n),10),
where n is the number of rows of datesArray (in this case approximately 2 millions) in order to get my result, but this approach is very slow.
So, I want to know a different way to do that.
Regards.
You could avoid for loops by using cellfun, let's say your date cell array is
dates = {'20120101', '20120102', '20120103'}
You can then convert them to your format as
cellfun(#(x)[x(1:4),'-',x(5:6),'-',x(7:8)], dates, 'Uniform', false)
Hope that helps.
If your date format is always "yyyymmdd" and it's in a linear cell array called datesArray, you could maybe do it by accessing the strings in datesArray and transforming them by inserting hyphens and concatenating the string.
for i=1:length(datesArray)
newDatesArray{i} = [datesArray{i}(1:4), '-', datesArray{i}(5:6), '-', datesArray{i}(7:8)];
end
Transform your dates into serial one and keep them! However, here's a solution:
% Create dummy dates (takes 10 seconds on my pc)
tic;d = cellstr(datestr(now-2e5+1:now,'yyyymmdd'));toc
% Convert to char, then concatenate with '-' and back to `cellstr()` (1 sec):
c = char(d);
dash = repmat('-',2e5,1);
c = cellstr([c(:,1:4) dash c(:,5:6) dash c(:,7:8)]);
So here my solution, which i think is quite nice!
dates = {'20120101', '20120102', '20120103'}
And you can convert using this :
cellfun(#(x)regexprep(num2str(x), '(?<=\d{4})\d{2}', '-$0'),dates,'Uniform',false)
The answer is similar to radarhead, but it uses the regexprep function instead.