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"]
Related
I want to make a Array of Arrays for Strings [[String]]() and be able to specify by index which inner list i want to append to
I have a var declared as:
var myList = [[String]]
I ideally want it to be something like this : [ ["a","b"], ["l","m"] ] and have the ability to specify which inner list gets the new element/ letter via a index
I have tried :
myList[index].insert("c", at: index) //gives and error saying index out of range
myList[index].append("c") //gives and error saying index out of range
if myList[index].isEmpty {
myList[index].append("c")
}//gives and error saying index out of range
but whenever i try to add to it i get an index out of range error as shown above.
The issue you are running into is that since you initialize myList as an empty array (var myList: [[String]] = []), you cannot reference items at specific indexes.
You can make a method like this to make sure you aren't accessing non-existant indexes:
func addToNested(_ index: Int, _ item: String) {
while index >= myList.count {
myList.append([])
}
myList[index].append(item)
}
This way it will check to see that you have enough arrays nested inside myList. That way if you call the following:
addToNested(0, "a")
addToNested(1, "l")
addToNested(0, "b")
addToNested(1, "m")
myList will be equal to [["a", "b"], ["l", "m"]]
You need to specify the size of the first dimension first. If you know exactly that you're gonna have n arrays, you can fix the problem by:
var myList: [[String]] = .init(repeating: [], count: n)
// which is shorthand for
var myList: [[String]] = Array(repeating: [], count: n)
// which can be rewritten like
var myList = Array<[[String]]>(repeating: [], count: n)
And you can use it like:
var myList: [[String]] = .init(repeating: [], count: 4)
myList[0].append("a")
myList[1].append("b")
myList[1].append("c")
myList[2].append(contentsOf: ["d", "f"])
myList[2].insert("e", at: 1)
print(myList)
> [["a"], ["b", "c"], ["d", "e", "f"], []]
Or if you know that it's going to be NxM matrix, you can also do
var myList: [[String]] = .init(repeating: .init(repeating: "", count: m), count: n)
I'm looking for a method that is similar to Array#combination, but the order matters.
Given this input:
array = ['a','b','c','d','e']
I'd like to get:
[['a','b','c'],['b','c','d'],['c','d','e']]
I'm trying to find the method that does this:
array = ['a','b','c','d','e']
x,a = 3,[]
until x > (ary.size) do
a += (0.upto(ary.size - x).map{|i| ary[i..(x-1)+i]} )
x += 1
end
The Enumerable documentation is your friend:
array = ['a','b','c','d','e']
array.each_cons(3).to_a
# => [["a", "b", "c"], ["b", "c", "d"], ["c", "d", "e"]]
each_cons(n) { ... }
Iterates the given block for each array of consecutive elements. If no block is given, returns an enumerator.
I want to insert item at specific index in Swift. But an error has occurred: Index is out of range
var a = [String]()
a.insert("a", atIndex: 3)
a.insert("b", atIndex: 1)
a.insert("c", atIndex: 0)
a.insert("d", atIndex: 2)
print(a)
If i have to use append or insert sequentially, it will break the order i wanted.
The answer by #fiks does explain the problem and a the correct solution if you want to use Array.
Dictionary
Since you want to perform random insertions, using a Dictionary instead of Array does seem a more flexible choice.
var dict: [Int:String] = [:]
dict[3] = "a"
dict[1] = "b"
dict[0] = "c"
dict[2] = "d"
print(dict) // [2: "d", 3: "a", 1: "b", 0: "c"]
print(dict.sort { $0.0.0 < $0.1.0}.map { $0.1 } ) // ["c", "b", "d", "a"]
You are trying to insert an item in the empty array at index 3. This causes the crash.
You may want to initialise the array with default values:
var a = Array<String>(count: 10, repeatedValue: "")
a.insert("a", atIndex: 3)
print(a)
But then you are not inserting, you are jus modifying the value, so you could achieve the same in this way:
var a = Array<String>(count: 10, repeatedValue: "")
a[3] = "a"
print(a)
The problem with your code is that the second parameter of insert must be less than or equal to the array's endIndex.
When you want to insert an element at index 3 to an array that has zero length, you can't! Because if there is an element at index 3, there must be an element at index 0, 1, 2 as well! That's how arrays work: it's sequential.
I guess you want the elements at index 0, 1 and 2 to be some default value. Then use this extension
extension Array {
mutating func insert(element: Element, atIndex index: Int, withDefaultValue value: Element) {
if self.endIndex < index {
let diff = index - endIndex
for _ in 0...diff {
self.append(value)
}
self[endIndex - 1] = element
} else {
insert(element, atIndex: index)
}
}
}
It's pretty much self-explanatory.
This can also be an XY problem. You might just need a [Int: String] for this. But without further info, I don't know.
I'm writing some code to filter out driving trips from the motion sensor. I figured out the best way to do this is to add a subarray to a nested array based on the following:
Detect the first occurrence of a confident automotive event
Add all the following motion events to the same array of the events until the first confident observation that says otherwise.
For example
automotive confidence 2 //Add
automotive confidence 2 //Add
automotive confidence 2 //Add
walking confidence 2 //Add the sub-array to the master array and start over on the next confident automotive event.
Currently i'm doing it this way:
//Remove all uncertain values.
let confidentActivities = activities!.filter{$0.confidence.rawValue == 2}
var needsNew = true
var automotiveActivities:Array<Array<CMMotionActivity>> = Array() //Master array to contain subarrays of automotiveactivity arrays
var automotiveActivitySession:Array<CMMotionActivity> = Array()
for activity in confidentActivities {
if activity.automotive && (!activity.cycling && !activity.running && !activity.walking){
if needsNew {
needsNew = false
}
automotiveActivitySession.append(activity)
} else {
if !needsNew {
//If user is no longer in car, store a cpoy of the session and reset the array
automotiveActivities.append(Array(automotiveActivitySession))
automotiveActivitySession = []
needsNew = true
}
}
}
This solution is not very elegant.
Is there any way to use Swift's Array.filter{} to make this sorting prettier?
Filter is not going to do it, but you can use reduce.
The example below shows how to collect runs of consecutive "A"s (denoting an automotive event) into arrays inside an array of arrays:
let data = ["A","A","A","B","A","A","B","A","A","A","A","B","B","B","A","B","A","A","A","A","A","A","B","A"]
var res = [[String]]()
_ = data.reduce("") { (last: String, current: String) in
if current == "A" {
if last != "A" {
res.append([String]())
}
res[res.count-1].append(current)
}
return current
}
print(res)
The prior value is passed to reduce's function as the first parameter. This makes it possible for the function to decide whether to append to the current list or to start a new list.
The result of this run is as follows:
[ ["A", "A", "A"]
, ["A", "A"]
, ["A", "A", "A", "A"]
, ["A"]
, ["A", "A", "A", "A", "A", "A"]
, ["A"]]
If you're after a pretty solution, you can use split to do this. You just have to provide it with a condition on what should be considered a separator. In your case, this will be any motion event that isn't an automotive one.
let arr = ["A","A","A","B","A","A","B","A","A","C","A","B","D","B","A","B","A","E","A","A","F","A","B","A","B"]
let split = arr.split {$0 != "A"} // insert your condition for whether the given element should be considered a 'seperator'
$0 here is the anonymous closure argument for an element in the array (as it iterates through). You can always expand the closure in order to make the namings more explicit, although it looks less elegant. For example:
let split = arr.split {element in
return element != "A"
}
This will return an array of ArraySlices like so:
[
ArraySlice(["A", "A", "A"]),
ArraySlice(["A", "A"]),
ArraySlice(["A", "A"]),
ArraySlice(["A"]),
ArraySlice(["A"]),
ArraySlice(["A"]),
ArraySlice(["A", "A"]),
ArraySlice(["A"]),
ArraySlice(["A"])
]
If you want them to be explicit Arrays, you can simply use map afterwards:
let split = arr.split {$0 != "A"}.map{Array($0)}
Returns:
[
["A", "A", "A"],
["A", "A"],
["A", "A"],
["A"], ["A"],
["A"],
["A", "A"],
["A"],
["A"]
]
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