I've created an Array as a lazy var:
lazy var info : [[String: AnyObject?]] = {
var dictionary = [[String: AnyObject?]]()
dictionary["Key1"] = ["A", "B", "C"]
dictionary["Key2"] = ["D", "E", "F"]
return dictionary
}()
and then call this later in titleForHeaderInSection as follows:
self.info[section]
but this results in the following error:
Cannot subscript a value of type '[[String : AnyObject?]]'
Should this not work?
You have there a dictionary, not an array. Your dictionary does have an array for each key but the dictionary itself is not an array. All of the keys therefore are strings (in your case "Key1" and "Key2") but you are trying to pass in an integer - "section". Instead of:
self.info[section]
You should use:
self.info["Key1"]![section]
As your code is written you are creating a Dictionary with String keys and [String] values.
So self.info["Key1"] would return ["A", "B", "C"]
Then you can do:
self.info["Key1"]![0] // "A"
Note: you need to unwrap the value returned from the dictionary as it can be Nil
Related
I have a source array with an unknown number of elements:
let sourceArray = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
I need to 'deal' those elements out into a given number of new arrays.
For example, given '3' empty arrays, the result would look like this:
let result = [["A", "D", "G"],["B", "E", "H"],["C", "F", "I"]]
This is what I've come up with, which technically works but feels pretty clunky. Any suggestions for improvement?
func createArrays(sourceArray: [String], count: Int) -> [[String]] {
var resultArrays = [[String]]()
for i in 0..<count {
var newArray = [String]()
var currentIndex = i
for (index, item) in sourceArray.enumerated() {
if index == currentIndex {
newArray.append(item)
currentIndex = currentIndex + count
}
}
resultArrays.append(newArray)
}
return resultArrays
}
Personally I would use reduce(into:).
extension Sequence {
func deal(into howMany: Int) -> [[Element]] {
self.enumerated().reduce(into: Array(repeating: [Element](), count: howMany)) {
$0[$1.offset % howMany].append($1.element)
}
}
}
Now you just say
let output = sourceArray.deal(into: 3)
or however many piles you want. It isn't very sophisticated but I like it because it does exactly what we intuitively would think of as dealing: it literally deals out the elements into piles, one at a time, exactly as you physically do when you deal out a deck of cards into hands, one card per pile round in a circle until the deck is exhausted.
Alexander's recommendation is one way to tackle the problem, but striding by the share count, once for each share, yields the same result as chunking and then transposing (except that transposing isn't defined when the chunks are not of equal counts).
["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"].distributedUniformly(shareCount: 4) as Array
[["A", "E", "I"], ["B", "F", "J"], ["C", "G"], ["D", "H"]]
import Algorithms
public extension Sequence {
/// Distribute the elements as uniformly as possible, as if dealing one-by-one into shares.
/// - Note: Later shares will be one smaller if the element count is not a multiple of `shareCount`.
#inlinable func distributedUniformly(shareCount: Int)
-> LazyMapSequence<Range<Int>, StrideSequence<DropFirstSequence<Self>>> {
(0..<shareCount).lazy.map {
dropFirst($0).striding(by: shareCount)
}
}
/// Distribute the elements as uniformly as possible, as if dealing one-by-one into shares.
/// - Note: Later shares will be one smaller if the element count is not a multiple of `shareCount`.
#inlinable func distributedUniformly(shareCount: Int) -> [[Element]] {
.init(distributedUniformly(shareCount: shareCount).map(Array.init))
}
}
So this question is a follow up to this one: swift string permutations allowing the same strings
There, I asked about all possible mutations that I can make with a defined set of strings. What I am trying to do next is to filter out all results that have the same combination, but in a different order.
So if the input is: ["AB", "AC", "CA", "CB"], the output should be ["AB", "AC", "CB"], since "AC" and "CA" have the same building blocks.
So my thought was to first sort each string alphabetically, and maybe then create a Set.
I am already stuck on the first part :(
let array = ["AB", "AC", "DC", "CA", "CB"]
print(type(of: array))
print(array)
let sortedArray = array.map{ $0.sorted() }
print(type(of: sortedArray))
print(sortedArray)
The output is:
Array<String>
["AB", "AC", "DC", "CA", "CB"]
Array<Array<Character>>
[["A", "B"], ["A", "C"], ["C", "D"], ["A", "C"], ["B", "C"]]
While I expected for the sortedArray:
["AB", "AC", "CD", "AC", "BC"]
Then I thought to join the individual strings back together:
print(array.map{ $0.joined() } )
Resulting in ambiguous reference to member 'joined()'
But how to fix this I don't understand.
I also saw this one: swift sort characters in a string where the following code is used:
var nonSortedString = "5121"
var sortedString = String(Array(nonSortedString.characters).sort())
But I don't see how to apply that using map and friends (after converting to Swift 4)
Any help appreciated.
If you want to take a string, sort its characters, and build a new string from that, in Swift 4 you can:
let string = "foobar"
let sortedString = String(string.sorted())
That results in:
"abfoor"
So, going back to your original problem, you can take you strings, which are a collection of permutations, and build a sorted array of combinations like so:
let permutations = ["AB", "AC", "DC", "CA", "CB"]
// build set of combinations where each string has, itself, been sorted alphabetically
let combinations = Set(permutations.map { String($0.sorted()) })
// convert set (which removed duplicates) back to an array and sort it
let result = Array(combinations).sorted()
That results in:
["AB", "AC", "BC", "CD"]
A different approach...
This solution uses another reduce function implementation from the Sequence protocol
let reduced = array.map({ String($0.sorted()) }).reduce(into: [String]() ){ (result, element) -> Void in
if !result.contains(element)
{
result.append(element)
}
}.sorted()
print(reduced)
The result is...
["AB", "AC", "BC", "CD"]
I am new to ruby and trying to create a method that takes a string and returns an array with each letter as their own index in an array.
def validate_word(word)
w=[]
word.downcase!
w << word.split(//)
return w
end
validate_word("abcABC")
=> [["a", "b", "c", "a", "b", "c"]]
I would like it to return
=>["a", "b", "c", "a", "b", "c"]
Thank you for looking at my code.
In your code you do not need to create a new array, since String#split returns array which you want. Also, Ruby returns last string of a method by default, so you can write:
def validate_word(word)
word.downcase!
word.split(//) # or you can chain methods: word.downcase.split('')
end
validate_word("abcABC")
=> ["a", "b", "c", "a", "b", "c"]
Note: do not use methods with exclamation mark (downcase!) except cases when you want modify source object. Use alternative methods(downcase) instead.
Scenario:
An array of strings, many are duplicated.
Goal:
Produce a UNIQUE array of strings.
Modus Operandi:
I was thinking of converting the array to a set of strings which become unique; from which to generate a new array of unique strings.
Question: How does one convert a Swift array into a Swift Set?
let nonUniqueArray = ["A", "B", "C", "C", "B", "A"]
let uniqueArray = Array(Set(nonUniqueArray))
print(uniqueArray)
produces
["C", "B", "A"]
Swift 2.2 produces exactly the same result as well.
Have you tried let myset = Set(myarray) ?
What could be the swift equivalent of following python code ?
array =[ "a", "b", "c"]
print(array[1:])
( Above statement prints every element from first index upto end of array.
Output ['b', 'c'])
Edit
Is there a way where this could be done with out using array.count ? Since the array.count is redundant if I say want every element from second position
With Swift 4, there is many ways to solve your problem. According to your needs, you may choose one of the six following patterns.
#1. Using Array dropFirst() method
let array = ["a", "b", "c"]
let arraySlice = array.dropFirst()
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]
#2. Using Array suffix(from:) method
let array = ["a", "b", "c"]
let arraySlice = array.suffix(from: 1)
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]
#3. Using Array suffix(_:) method
let array = ["a", "b", "c"]
let arraySlice = array.suffix(array.endIndex.advanced(by: -1))
// let arraySlice = array.suffix(array.count - 1) // also works
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]
#4. Using Array subscript(_:) and CountableRange
let array = ["a", "b", "c"]
let range = array.startIndex.advanced(by: 1) ..< array.endIndex
// let range = 1 ..< array.count // also works
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]
#5. Using Array subscript(_:) and CountableClosedRange
let array = ["a", "b", "c"]
let range = 1 ... array.count - 1 // also works
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]
#6. Using Array subscript(_:) and CountablePartialRangeFrom
let array = ["a", "b", "c"]
let range = 1...
let arraySlice = array[range]
let newArray = Array(arraySlice)
print(newArray) // prints ["b", "c"]
You can get sub range of an swift array like that:
let array =[ "a", "b", "c"]
//be sure that your array.count has more than 1 item (in this case)
let subArray1 = array[1..<array.count]
print(subArray1)
//or
let subArray2 = array[1...array.count-1]
print(subArray2)
This is 2 notes from Swift Programming Language book
“Use .. to make a range that omits its upper value, and use ... to
make a range that includes both values.”
And
“If you try to use subscript syntax to retrieve or set a value for an
index that is outside of an array’s existing bounds, you will trigger
a runtime error. However, you can check that an index is valid before
using it, by comparing it to the array’s count property. Except when
count is 0 (meaning the array is empty), the largest valid index in an
array will always be count - 1, because arrays are indexed from zero.”
You can achieve what you're looking for in the following way:
1. Create a custom struct to store a start and end index. If startIndex or endIndex is nil this will be taken to mean the range extends infinitely in that direction.
struct UnboundedRange<Index> {
var startIndex, endIndex: Index?
// Providing these initialisers prevents both `startIndex` and `endIndex` being `nil`.
init(start: Index) {
self.startIndex = start
}
init(end: Index) {
self.endIndex = end
}
}
2. Define operators to create an BoundedRange as having to use the initialisers will lead to some quite unsightly code, in my option.
postfix operator ... {}
prefix operator ... {}
postfix func ... <Index> (startIndex: Index) -> UnboundedRange<Index> {
return UnboundedRange(start: startIndex)
}
prefix func ... <Index> (endIndex: Index) -> UnboundedRange<Index> {
return UnboundedRange(end: endIndex)
}
Some example usage:
1... // An UnboundedRange<Int> that extends from 1 to infinity.
...10 // An UnboundedRange<Int> that extends from minus infinity to 10.
3. Extend the CollectionType so it can handle UnboundedRanges.
extension CollectionType {
subscript(subrange: UnboundedRange<Index>) -> SubSequence {
let start = subrange.startIndex ?? self.startIndex
let end = subrange.endIndex?.advancedBy(1) ?? self.endIndex
return self[start..<end]
}
}
4. To use this in your given example:
let array = ["a", "b", "c"]
array[1...] // Returns ["b", "c"]
array[...1] // Returns ["a", "b"]