How to add a text prefix to an array on Swift? - ios

Right now I have a array that when printed just displays what number I submitted. I would like the word "car" to be in front of every array number. For example: I enter 1 and 2 in the array. When the array is called it would look like [car 1, car 2] not [1,2].
I have added my array variable and what I am calling to print the array:
var arrayOfInt = [Int]()
label.text = String(describing: arrayOfInt)

Try this:
let arrayOfInt: [Int] = [1, 2]
let cars = arrayOfInt.map { "car \($0)" }
as a result, the cars array will be:
["car 1", "car 2"]
finally, convert to string as before:
label.text = String(describing: cars)
The Array.map function returns an array containing the results of mapping the given closure over the array's elements. In other words, it tranforms one array into another one by applying the specified function on each element.

Related

Create a team generator with a given number of teams

I would like to take an array of [String] and split it up into a given number of groups.
I have tried using this extension
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to:count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
to split the array into a given number of elements per subarray, which for that function it works.
But to split it into a desired number of subarrays, I tried dividing the array.count by the desired number of teams, which works but only in certain circumstances.
If there are any extra elements, it puts them into an extra subarray at the end, and the number needs to come out even if I want this to work perfectly, which is the minority of the time.
So I guess this array.chunked function is not the solution in any way.
Maybe there is a way to do it with a for loop by taking an array.randomElement(), adding that to a variable (which would be a team) and then removing that element from the original array, and iterating over it until the original array is empty. And end up with an array of subarrays which would be the teams, or just separate variables which would be the teams. It could be any of those options.
Any ideas on how to do this?
Think about how you deal cards.
If you have 7 players, you start with one player and go around, giving one card at a time to each player. At the end, you may run out of cards before giving everybody the same number of cards. Some people may have n cards, and some may have n-1. That's the best that you can do.
You could implement the same thing with a source array and your destination arrays. Remove one element at a time from the source array, and "round-robbin" add it to one of the destination arrays until the source array is exhausted.
That code might look like this:
func splitArray<T>(array: [T], subArrayCount: Int) -> [[T]] {
// Create an empty array of arrays
var result = [[T]]()
// Create the empty inner string arrays
for _ in 1...subArrayCount {
let innerArray = [T]()
result.append(innerArray)
}
for (index, element) in array.enumerated() {
result[index % subArrayCount].append(element)
}
return result
}
And to test it:
let string = "Now is the time for all good programmers to babble incoherently. The rain in spain falls mainly on the plain. Fourscore and seven years ago our forefathers brought forth to this continent a new nation conceived in liberty and dedicated to the cause that all men are created equal."
let array = string.split(separator: " ")
.map { String($0) }
let subArrays: [[String]] = splitArray(array: array, subArrayCount: 5)
for (index, array) in subArrays.enumerated() {
let countString = String(format: "%2d", array.count)
print ("Array[\(index)]. Count = \(countString). Contents = \(array)")
}
The output of that test is:
Array[0]. Count = 10. Contents = ["Now", "all", "incoherently.", "falls", "Fourscore", "our", "this", "conceived", "to", "men"]
Array[1]. Count = 10. Contents = ["is", "good", "The", "mainly", "and", "forefathers", "continent", "in", "the", "are"]
Array[2]. Count = 10. Contents = ["the", "programmers", "rain", "on", "seven", "brought", "a", "liberty", "cause", "created"]
Array[3]. Count = 10. Contents = ["time", "to", "in", "the", "years", "forth", "new", "and", "that", "equal."]
Array[4]. Count = 9. Contents = ["for", "babble", "spain", "plain.", "ago", "to", "nation", "dedicated", "all"]

How to parse json correctly in ios?

For example I need to get all english "text" values of "ex" scope from JSON example
What I do:
let result = json["def"].arrayValue.map({ $0["tr"].arrayValue.map { $0["ex"] } })
but at as a result I got a double massive and if I intend to get all "text" then I will get a triple array. Guess should be another more elegant approach to this task. Is anyone can show a really good solution?
If your expression gives 3 arrays of Strings you could add .reduce([], +) at the end to join the 3 arrays into
one.
EDIT:
I was typing from memory, and said the wrong thing. You would use reduce, not joined.
let result = json["def"]
.arrayValue
.map({ $0["tr"].arrayValue.map { $0["ex"] } })
.reduce([], +)
That should give you what you want.
EDIT #2:
The reduce function operates on sequences (like arrays). It takes an "initial result" value that seeds the process, and then a closure that operates on 2 elements, and returns a result. (a "binary" closure)
The + operator is actually a binary closure in Swift. It takes 2 elements and returns a single result, so you can simply pass in + instead of a closure. For arrays, + returns the result of combining the arrays.
So when you use reduce() on an array of arrays, and [] as the initial result, it combines [] with the first array, then the result of each + operator with the next entry in the array.
Take this simplified code for example:
//Start with an array of arrays of strings
let arrays = [
["string1", "string2", "string3"],
["string4", "string5", "string6"],
["string7", "string8", "string9"]
]
//First loop through the outer arrays and log their contents
for (index, object) in arrays.enumerated() {
print("array[\(index)] = \(object)")
}
//Now combine the outer arrays into a single array
let combined = arrays.reduce([], + )
//Now print the entries in the combined array
print("\n---- combined arrays ----")
for (index, object) in combined.enumerated() {
print("array[\(index)] = \(object)")
}
That produces the following output:
array[0] = ["string1", "string2", "string3"]
array[1] = ["string4", "string5", "string6"]
array[2] = ["string7", "string8", "string9"]
---- combined arrays ----
array[0] = string1
array[1] = string2
array[2] = string3
array[3] = string4
array[4] = string5
array[5] = string6
array[6] = string7
array[7] = string8
array[8] = string9

IOS Swift 2 - How to construct multidimensional array

How can I achieve the following output:
rsPool[0][p1] = "123"
rsPool[0][p2] = "234"
rsPool[1][p1] = "abc"
rsPool[1][p2] = "bcd"
I deserialized from JSON output, which has the following data
first dimention > type (1 to 7)
second dimention > p1...P10
value > xxxx
I have tried to create:
var rspool : [Int: String] : []
but I don't know how to add/append to the array.
You define multidimensional array by use square brackets multiple times:
var rspool: [[String]] = [["123", "234"], ["abc", "bcd"]]
print(rspool[0][0])
print(rspool[0][1])
print(rspool[1][0])
print(rspool[1][1])
//123
//234
//abc
//bcd
This is array of arrays of String.
Dynamic array
Usually you use dynamically changed array sizes, by using Array methods like append, insert and removeAtIndex. Lets compose given array from empty array:
var rspool = [[String]]()
rspool.append([String]()) //adding first line; now we can access it by rspool[0]
rspool[0].append("abc")
rspool[0].append("bcd")
//we started from second line for to show example with insert:
rspool.insert([String](), atIndex: 0) //inserting new line as first line
rspool[0].append("123")
rspool[0].append("234")
print(rspool)
//[["123", "234"], ["abc", "bcd"]]
You need always be careful with accessing to this array by indexes, since you can receive "index out of range" exception. You read and overwrite existed values in array directly by indexes:
let veryFirst = raspol[0][0]
raspol[0][0] = "456"
Static array
If you wish manipulate your array only by indexes, aka matrix style, you need to set constant dimensions and initialize all array first. Optional type as element type and repeated values are useful then:
let m = 3
let n = 5
var rspool = [[String?]](count: m, repeatedValue: [String?](count: n, repeatedValue: nil))
Now you can read an write elements by indexes:
rspool[0][0] = "123"
rspool[0][1] = "234"
rspool[1][0] = "abc"
rspool[1][1] = "bcd"
print(rspool)
//[[Optional("123"), Optional("234"), nil, nil, nil], [Optional("abc"), Optional("bcd"), nil, nil, nil], [nil, nil, nil, nil, nil]]
Matrix- style array numerating example:
rspool[2][4] = "END"
for i in 0..<m {
for j in 0..<n {
print("\(rspool[i][j] ?? ".")\t", terminator: "")
}
print()
}
//123 234 . . .
//abc bcd . . .
//. . . . END
Your data seems to be this:
var rsPool = [
[
"p1": "123",
"p2": "234"
],
[
"p1": "abc",
"p2": "bcd"
]
]
which is of type [Dictionary<String, String>]
So the declaration should be:
var rsPool: [[String:String]]
Here's Playground reference:

Finding the index of 'NSURL item' in 'NSURL array'

I have 2 arrays of [NSURL] and they have the same elements with different order. I am trying to use the array1's indexpath to get the member, and detect member's indexPath in the other array.
I couldn't figure out if I can detect the member's index on type NSURL. I thought one way could be using for loop for the second array, however the way I could think of was..
For loop through the array2 and convert each to string to have a [string] and using another for loop to find the index of the string that I'm looking for
let array1 = [NSURL]()
let array2 = [NSURL]()
array1 = [abc, qwe, jkl]
array2 = [jkl, abc, qwe]
// To wrap up..
// For jkl, I want to use array1[2] and get array2[?]
let searchIndex = 2
if array1[2].absoluteString.isNotEmpty {
let stringToSearch = array1[2].absoluteString
}
let index = array2.indexOf { $0.absoluteString == array1[2].absoluteString }

An Array of Doubles from Two Arrays of Strings

Say I have two arrays:
let arrayOne = ["Hi", "Hi", "Hello", "Not Hey", "Howdy", "Hi"]
let arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy", "Hi", "Hi"]
and I have this for loop that gets the percent similarity of the doubles:
var matches = 0
for (index, item) in enumerate(arrayOne) {
if item == arrayTwo[index] {
matches++
}
}
However, what if those arrays are longer and I want data points of those similarities instead of one single calculation. What kind of a function could I write where it takes the first 5 elements off the array, returns their similarity with the for loop, and moves on to the next 5? ie. it would be a function that takes two string arrays and returns an array of doubles. I am sure this is a simple question but I do not know how to approach taking 5 array elements at a time and then returning an array of doubles (like data points the the string array similarities).
I’m not clear quite what you’re asking, however, you might find playing around with zip, map, and reduce helpful.
For example, you could rewrite your original loop like this (assuming Swift 2.0, you’d have to rearrange slightly for 1.2):
zip(arrayOne, arrayTwo).reduce(0) { $0 + ($1.0 == $1.1 ? 1 : 0) }
// returns 4
zip creates a new sequence of the pairs of elements at each corresponding position.
reduce takes a starting value, then keeps a running value by applying a function to the current value and the next value in the sequence – bearing in mind this is a sequence of pair elements, you want to add 1 when they are the same, 0 when they aren’t. This then gives you a count of the positions where both match.
If instead you wanted an array, with true representing a match at that point, and false if different, you could use map:
zip(arrayOne, arrayTwo).map(==)
// returns [true, false, false, false, false, true]
If on the other hand you wanted a list of the differences in string length between the two strings at each position, you could change it to:
zip(arrayOne, arrayTwo).map { (a,b) in
a.characters.count - b.characters.count
}
// returns [0, -3, 2, -2, 3, 0]
As some have suggested, Set might help, e.g.:
let commonElements = Set(arrayOne).intersect(arrayTwo)
// returns strings present in both e.g. {"Hi", "Hello”}
This is a good approach if you are OK treating your data as a set i.e. order doesn’t matter and duplicates can be ignored. If order and dupes do matter, you probably have to stick with arrays.
Take a look at this. I think it does what you are asking. By introducing a count variable to keep track of the number of items you have processed, you will know when to update your counts array:
var matches = 0
let arrayOne = ["Hi", "Hi", "Hello", "Not Hey", "Howdy", "Hi", "a", "b", "c"]
let arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy", "Hi", "Hi", "a", "B", "C"]
var count = 0
var counts:[Int] = []
for (index, item) in enumerate(arrayOne) {
if item == arrayTwo[index] {
matches++
}
// Have we done 5? If so, time to update counts array
if ++count == 5 {
counts.append(matches)
count = 0
matches = 0
}
}
// If we didn't have 5, just append the matches for the remaining items
if count > 0 {
counts.append(matches)
}
println(counts) // prints "[1, 2]"
Right - so I think I understand what you're looking for: you want to have a matches function like the one you've written that works for chunks of a certain number of elements. First off, you're going to need a chunk function. There's a good discussion of them here, but they're for arrays, and you're going to want to zip your two arrays together here, so you'll need one for SequenceType. This works:
public extension SequenceType {
/// Returns an array of arrays of n non-overlapping elements of self
/// - Parameter n: The size of the chunk
/// ```swift
/// [1, 2, 3, 4, 5].chunk(2)
///
/// [[1, 2], [3, 4], [5]]
/// ```
func chunk(_ n: Int) -> [[Generator.Element]] {
var g = self.generate()
var ret: [[Generator.Element]] = [[]]
while let next = g.next() {
if ret.last!.count < n {
ret[ret.endIndex.predecessor()].append(next)
} else {
ret.append([next])
}
}
return ret
}
}
Then, you need a function that counts the matches in two arrays. You could inline it with a closure, or you could define it separately, it doesn't make much of a difference.
func matchesEvery<
S0 : SequenceType,
S1 : SequenceType,
T : Equatable where
S0.Generator.Element == T,
S1.Generator.Element == T
>(_ n: Int, s0: S0, s1: S1) -> [Int] {
return zip(s0, s1)
.chunk(5)
.map { $0.reduce(0) { $1.0 == $1.1 ? $0 + 1 : $0 } }
}
That will return:
let arrayOne = ["Hi", "Hi", "Hello", "Not Hey", "Howdy", "Hi"]
let arrayTwo = ["Hi", "Hello", "Hey", "Not Howdy", "Hi", "Hi"]
matchesEvery(5, s0: arrayOne, s1: arrayTwo) // [1, 1]
Since in the first five there's one match, and in the last there is one as well.

Resources