I need to convert an array.count to String values for the count, i.e.
array.count = 5 should return ["0","1","2","3","4"]
I've tried
var strRow = array.map { String($0) }
return strRow
but it's not working the way it should. Any help will be appreciated.
Try
return Array(0...array.count)
if you want array of Strings, then just map it
Array(0...array.count).map{String($0)}
Try this (Hint are in the Code Comments):
var array = [1, 2, 3, 4, 5] // array.count = 5
var stringArray = [String]()
// 0 ... array.count to go from 0 to 5 included
for index in 0 ... array.count {
// append index with cast it to string
stringArray.append(String(index))
}
print(stringArray)
// result -> ["0","1","2","3","4","5"]
In your question you give an example that array of count 5 should be transformed to ["0","1","2","3","4","5"], that's a 6-count array, are you sure this is what you need? I will assume that you want 5-count array to be transformed to ["0","1","2","3","4"], please correct me in the comments if I'm wrong.
Here's the solution I propose:
let array = [5,5,5,5,5] // count 5
let stringIndices = array.indices.map(String.init)
// ["0", "1", "2", "3", "4"]
Related
I have to filter an array having the most occurrences of element.
Initial Array :
let array1 = [1,2,3,2,4,2,5,3]
let array2 = ["abc", "def", "abc", "ert", "def", "abc"]
After Filtering, Final Array :
let filteredArray1 = [2,2,2]
let filteredArray2 = ["abc","abc","abc"]
I got the idea to get the count of elements from here:
How to count occurrences of an element in a Swift array?
Like getting the count of "abc" :
array2.filter{$0 == "abc"}.count
But is there any way to get the filtered array ?
You can group the items into a dictionary and compare the number of items in each group
let mostFrequent = Dictionary(grouping: array1, by: {$0})
.max(by: {$0.value.count < $1.value.count})?.value ?? []
The issue with the above is that if there are two or more values with the same count only one will be selected.
The below solution handles when there are multiple max counts, I couldn't write it as a single line expression though
let dictionary = Dictionary(grouping: array1, by: {$0})
let max = dictionary.max(by: {$0.value.count < $1.value.count})?.value.count ?? 0
let mostFrequent = dictionary.filter { $0.value.count == max }.values
Using NSCountedSet 🔢
You can define this extension for the Array type
extension Array where Element: Equatable {
func filteredByMostPopular() -> [Element] {
let countedSet = NSCountedSet(array: self)
let mostPopularElement = self.max { countedSet.count(for: $0) < countedSet.count(for: $1) }
return self.filter { $0 == mostPopularElement }
}
}
How does it work?
The extension uses NSCountedSet to find the "most popular" element.
If 2 or more elements are the most popular the first one is choosen.
Then the array is filtered using the most popular element.
Test
array1.filteredByMostPopular() // [2, 2, 2]
array2.filteredByMostPopular() // ["abc", "abc", "abc"]
I have an array of arrays containg int, so let pairs:[[Int]].
I am looking for an elegant way to extract similar elements.
For example my pairs variable could contain something like: [ [1,2], [4,6], [1,2] ]
I would like to extract any array that occurs more than once like [1,2].
In the example [ [1,2], [4,6], [1,2], [3,7], [4,6] ] I would like to extract both [1,2] and [4,6].
This seemed trivial at first, but every go I had at it became very cumbersome with many "helper arrays" and nested "for loops". There surely is a simpler way in Swift, right?
Thanks
Here the way using just one helper Dictionary and one loop:
let pairs = [[1,2], [4,6], [1,2]] // The original array
var pairCount = [NSArray : Int]() // This is helper dictionary. The key is the array, the value is - how much time it appears in the source array. I use NSArray because swift array does not conform to Hashable protocol.
var newPairs = [[Int]]()
for pair in pairs { // Iterate over our pairs
var count: Int = pairCount[pair as NSArray] ?? 0 // If we already have a pair in our dictionary get count of it in array otherwise het 0
count += 1 // increase counter
pairCount[pair as NSArray] = count // save in dictionary
}
let pairsWithCountMoreThanOne = pairCount.flatMap({$1 > 1 ? $0 : nil}) // here we get the result
for pair in pairsWithCountMoreThanOne { // Just print it
print("\(pair)")
}
This code may not be memory efficient for large arrays or large objects but it is really trivial.
Please check the below :
let pairs = [ [1,2], [4,6], [1,2], [3,7], [4,6], [3,5], [4,6] ]
var repeats = [[Int]]()
pairs.forEach { (i) in
let count = (pairs.filter{ return $0 == i }).count
if count > 1 {
if !repeats.contains(where: { (pair) -> Bool in
return pair == i
}) {
repeats.append(i)
}
}
}
print(repeats) // Output is : [[1, 2], [4, 6]]
My question:
This answer explains how to convert a String containing elements separated by spaces into an array.
let numbers = "1 2 3 4"
let numbersArray = numbers.components(separatedBy: " ")
print(numbersArray)
// output: ["1", "2", "3", "4"]
// but I want: [1, 2, 3, 4]
However, I'm trying to make an array without quotation marks, because I'm making an array of numbers, not strings.
My attempts:
I tried removing all quotation marks from numbersArray, but this didn't work as it's an array, not a string.
numbersArray.replacingOccurrences(of: "\"", with: "") // won't work
I tried something different: I tried adding each element in the array to a new array, hoping that new array wouldn't contain quotation marks. I got an error, though:
let numbers = "1 2 3 4" // string to be converted into array without quotes
let numbersArray = numbers.components(separatedBy: " ") // convert string into array with quotes
var newNumbersArray = [String]() // new blank array (which will be without quotes)
for i in numbersArray { // for each item in the array with quotes
newNumbersArray += i // (hopefully) add the item in the new array without quotes
}
print(newNumbersArray) // print the new array
This gives me an error:
Swift:: Error: cannot convert value of type '[String]' to expected argument type 'inout String'
newNumbersArray += i
You can apply a flatMap call on the [String] array resulting from the call to components(separatedBy:), applying the failable init(_:radix:) of Int in the body of the transform closure of the flatMap invokation:
let strNumbers = "1 2 3 4"
let numbersArray = strNumbers
.components(separatedBy: " ")
.flatMap { Int($0) }
print(numbersArray) // [1, 2, 3, 4]
print(type(of: numbersArray)) // Array<Int>
You can try this:
var newArray = [Int]()
for item in numbersArray{
newArray.append(Int(item))
}
print(newArray)
Swift 3.0
Try this.. Chaining method makes it easy.
let temp = "1 2 3 4 5 6"
var numbers: [Int] = []
temp.components(separatedBy: " ").forEach { numbers.append(Int($0)!) }
print(numbers) //[1, 2, 3, 4, 5, 6]
Below I am trying to fetch the i'th element of the ArraySlice draggignFan. The code builds fine (no warnings) but the program dies at runtime on the line where I try to index the slice like a normal array:
var draggingFan : ArraySlice<Card>?
...
if let draggingFan = draggingFan {
for i in 1 ..< draggingFan.count {
let card = draggingFan[i] // EXECUTION ERROR HERE
...
}
}
According to the docs there is a first and last method (which I use elsewhere with no problem). So how do I index an ArraySlice in Swift? (Note: I am intentionally skipping the 0'th index in the slice -- that's needed elsewhere).
The indices of the ArraySlice still match those of the original array. In your case, you are accessing index 1 which is not in your slice. If you offset the index by draggingFan.startIndex it will work:
if let draggingFan = draggingFan {
for i in 1 ..< draggingFan.count {
let card = draggingFan[draggingFan.startIndex + i]
...
}
}
Alternatively:
if let draggingFan = draggingFan {
for i in draggingFan.startIndex + 1 ..< draggingFan.endIndex {
let card = draggingFan[i]
...
}
}
This will access the values from the second element in the slice to the last element in the slice:
let original = [1,2,3,4,5,6] // Int array to demonstrate
var draggingFan : ArraySlice<Int>?
draggingFan = original[1...4] // create the slice
if let draggingFan = draggingFan {
// so there's no errors just slice the slice and iterate over it
for i in draggingFan[(draggingFan.startIndex+1)..<draggingFan.endIndex] {
print(i, terminator: ", ")
}
}
Output:
3, 4, 5,
The reason you are having this problem is that the slice maintains the original index numbers of the sequence you got it from. Thus, element 1 is not in this slice.
For example, consider this code:
let arr = [1,2,3,4,5,6,7,8,9]
let slice = arr[2...5]
Now what is slice[1]? It isn't 4, even though that is the second thing in the slice. It's 2, because the slice still points into the original array. In other words, slice[1] is out of the slice's range! That is why you're getting a runtime error.
What to do? Well, the actual indexes of the slice are its indices. That is what you want to cycle thru. But... You don't want the first element pointed to by the slice. So you need to advance the startIndex of the range you're going to iterate through. Thus:
if let draggingFan = draggingFan {
var ixs = draggingFan.indices
ixs.startIndex = ixs.startIndex.advancedBy(1)
for i in ixs {
// ... now your code will work ...
}
}
However, in my view, there's no need to index the slice at all, and you shouldn't be doing so. You should cycle through the slice itself, not thru its indexes. You have this:
for i in 1 ..< draggingFan.count
But that is much like saying
for aCard in draggingFan
...except that you want to drop the first element of the slice. Then drop it! Say this:
for aCard in draggingFan.dropFirst()
To see that this will work, try this in a playground:
let arr = [1,2,3,4,5,6,7,8,9]
let slice = arr[2...5]
for anInt in slice.dropFirst() {
print(anInt) // 4, 5, 6
}
As you can see, we are cycling through exactly the desired elements, with no reference to index numbers at all.
To iterate over the elements in the slice:
draggingFan?.forEach({ (element)
...
})
As far as I know, the get a specific element, it needs to be converted back to an array e.g.
let draggingFanArray = Array(draggingFan!)
Here's the playground code I used to toy around with various scenarios:
import Cocoa
var a: Array<Int>?
var b: ArraySlice<Int>?
a = [1, 2, 3, 4, 5, 6, 7]
b = a![3...5]
let count = b!.count
b!.forEach({ (element) in
print("\(element)")
})
let c = Array(b!)
print(c[2])
edit ArraySlice extension though:
extension ArraySlice {
func elementAtIndex(index: Int)->AnyObject?{
return Array(self)[index] as? AnyObject
}
}
If I have an array:
var arr = [1, 2, 3, 4, 5, 6, 7] // [1, 2, 3, 4, 5, 6, 7]
And I take a slice of the array:
let slice = arr[3..<arr.count] // [4, 5, 6, 7]
This slice will have a startIndex of 3, which means that indexing starts at 3 and ends at 6.
Now if I want a slice containing everything but the first element, I can use the dropFirst() method:
let sliceMinusFirst = slice.dropFirst() // [5, 6, 7]
And at this point, sliceMinusFirst has a startIndex of 4, which means my indexes range from 4 to 6.
Now if I wish to iterate over these to do something with the items, I can do the following:
for item in sliceMinusFirst {
print(item)
}
Alternatively, I can do it with forEach:
sliceMinusFirst.forEach { item in
print(item)
}
By using these forms of iteration, the fact that the startIndex is nonzero doesn't even matter, because I don't use the indices directly. And it also doesn't matter that, after taking a slice, I wanted to drop the first item. I was able to do that easily. I could have even done that at the time I wanted to do the iteration:
slice.dropFirst().forEach { item in
print(item)
}
Here I dropped the first item from the original slice, without creating any intermediate variables.
Remember that if you need to actually use the index, you're probably doing something wrong. And if you genuinely do need the index, make sure you understand what's going on.
Also if you want to get back to zero-based indexing once you make a slice, you can create an array from your slice:
let sliceArray = Array(slice) // [4, 5, 6, 7]
sliceArray.startIndex // 0
I am kinda stumped on figuring this out. I want to populate an array with the string values that comes from a for-in loop.
Here's an example.
let names = ["Anna", "Alex", "Brian", "Jack"]
for x in names {
println(x)
}
The current x value would generate 4 string values (Anna, Alex, Brian, Jack).
However I need some advice in going about getting these four values back into an array. Thank you in advance.
Whatever is on the right side of a for - in expression must be a SequenceType. Array, as it happens, can be initialised with any SequenceType. So if you're just doing something like this:
var newArray: [String] = []
for value in exoticSequence {
newArray.append(value)
}
The same thing can be accomplished (faster), by doing this:
let newArray = Array(exoticSequence)
And it doesn't matter what type exoticSequence is: if the for-in loop worked, Array() will work.
However, if you're applying some kind of transformation to your exoticSequence, or you need some kind of side effect, .map() might be the way to go. .map() over any SequenceType can return an array. Again, this is faster, and more clear:
let exoticSequence = [1, 2, 3]
let newArray = exoticSequence.map {
value -> Int in
// You can put whatever would have been in your for-in loop here
print(value)
// In a way, the return statement will replace the append function
let whatYouWouldHaveAppended = value * 2
return whatYouWouldHaveAppended
}
newArray // [2, 4, 6]
And it's equivalent to:
let exoticSequence = [1, 2, 3]
var newArray: [Int] = []
for value in exoticSequence {
print(value)
let whatYouWouldHaveAppended = value * 2
newArray.append(whatYouWouldHaveAppended)
}
newArray // [2, 4, 6]