What's the difference between `Int...` and `[Int]` in Swift? - swift

// first segment
func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, condition: lessThanTen)
// second segment
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(42, 597, 12)
What's the difference between list in segment 1 and numbers in segment 2? Why one is [Int] another is Int...?
I try to exchange them in playground, error was shown.

[Int]
This indicates the parameter is a array type.
Int...
This indicates the parameter is a variadic parameter.
A variadic parameter accepts zero or more values of a specified type.
Difference
A variadic parameter is used as a constant array within function body, the difference happens in calling function, we can call function with variadic parameter in none parameter style, like function_variadic_type(), and function with array type can't do this, there must be a array passed into function, like function_array_type([1, 2]).

It has no difference. Your code is fine. You just have to delete 'condition' in line 17.
The code should be like this
func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, lessThanTen)
// second segment
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(42, 597, 12)

Related

How to check if a value in a dictionary has duplicates?

The algorithm below checks to see if an array has at least two or more duplicates. It uses a dictionary to store the occurrences; the time complexity is linear because it has to traverse the dictionary to see if a key occurs twice. In swift, how can I look up a value to see if it occurs more than twice in constant time ?
func containsDuplicate(_ nums: [Int]) -> Bool {
var frequencyTable = [Int:Int]()
for num in nums {
frequencyTable[num] = (frequencyTable[num] ?? 0 ) + 1
}
for value in frequencyTable.values{
if value >= 2 {
return true
}
}
return false
}
containsDuplicate([1,1,2,3,3,3,3,4])
The second loop is not necessary if the first loop checks if the current element has already been inserted before, and returns from the function in that case:
func containsDuplicate(_ nums: [Int]) -> Bool {
var frequencyTable = [Int:Int]()
for num in nums {
if frequencyTable[num] != nil {
return true
}
frequencyTable[num] = 1
}
return false
}
Then it becomes apparent that we don't need a dictionary, a set is sufficient:
func containsDuplicate(_ nums: [Int]) -> Bool {
var seen = Set<Int>()
for num in nums {
if seen.contains(num) {
return true
}
seen.insert(num)
}
return false
}
This can be further simplified: The “insert and check if element was already present” operation can be done in a single call:
func containsDuplicate(_ nums: [Int]) -> Bool {
var seen = Set<Int>()
for num in nums {
if !seen.insert(num).inserted {
return true
}
}
return false
}
This is similar to the solution from this answer
return nums.count != Set(nums).count
but possibly more efficient: The function returns immediately when a duplicate element has been detected.
Finally we can make the function generic, so that it works with all arrays of a hashable type:
func containsDuplicate<T: Hashable>(_ array: [T]) -> Bool {
var seen = Set<T>()
for element in array {
if !seen.insert(element).inserted {
return true
}
}
return false
}
Example:
print(containsDuplicate([1,1,2,3,3,3,3,4])) // true
print(containsDuplicate(["A", "X"])) // false
Or as an extension for arbitrary collections of a hashable type:
extension Collection where Element: Hashable {
func containsDuplicate() -> Bool {
var seen = Set<Element>()
for element in self {
if !seen.insert(element).inserted {
return true
}
}
return false
}
}
print([1,1,2,3,3,3,3,4].containsDuplicate())
print(["A", "X"].containsDuplicate())
You just want to know if it has duplicate, you can use use set and compare the length.
func containsDuplicate(_ nums: [Int]) -> Bool {
return Set(nums).count != nums.count
}
like this examples, because the set remove the duplicate values.

Largest Even Number in an Array using Swift

I'm a beginner in Swift, I'm trying to make a function that determines the largest even number in an array, here's my code that's not working:
func largestEven(array: [Int]) -> Int {
let array = [5,12,6,8]
var evenArray = array.filter({$0 % 2 == 0})
let highestEven = evenArray.max()
return highestEven
}
print(largestEven(array: [5,12,6,8]))
Change
func largestEven(array: [Int]) -> Int {
to
func largestEven(array: [Int]) -> Int? {
The reason is that max() yields an Optional Int, because the array might be empty. So you cannot return a simple Int; you must return that Optional.
Not sure why you define a local array in your function.
A simple implementation could be something like (note the optional Int as return type):
func largestEven(array: [Int]) -> Int? {
array.filter { $0.isMultiple(of: 2) }.max()
}

Form an array of Integers from integer value [duplicate]

This question already has answers here:
Break A Number Up To An Array of Individual Digits
(6 answers)
Closed 3 years ago.
Not sure how tag a question. I want to create an array of Int values from Int value. For example, if i have 1234 i want to output [1,2,3,4], for 8765 [8,7,6,5] etc. Function should look like:
private static func formAnArray(_ value: Int) -> [Int] {
// code
}
You can convert number to String and map it to array:
private static func formAnArray(_ value: Int) -> [Int] {
return String(value).compactMap { Int(String($0)) }
}
Another way (preferred for big numbers) is by using combination of % and /:
private static func formAnArray(_ value: Int) -> [Int] {
var value = value
var result: [Int] = []
while value > 0 {
result.insert(value % 10, at: 0)
value /= 10
}
return result
}
You can use compactMap to get and convert digits to an array of int
print(formAnArray(value: 1234))
func formAnArray(value: Int) -> [Int] {
let string = String(value)
return string.compactMap{Int(String($0))}
}

Swift function to find first element of collection matching a predicate?

If xs is a collection and pred is a closure that returns a Bool, is there a built-in function that does the following?
xs.filter(pred).first
This gets the first element of a collection matching the predict, or nil if there is no match. Not interested in the index, but the element itself.
No there isn't, but you can write one yourself like this:
extension SequenceType {
func first(#noescape pred: Generator.Element throws -> Bool) rethrows -> Generator.Element? {
return try filter(pred).first
}
}
EDIT: This version isn't optimal, since the filter creates a whole new array, even though only the first element would be needed. As noted by Martin R, lazy.filter also doesn't work for. This would be necessary to make it work with lazy:
extension CollectionType {
func first(pred: Generator.Element -> Bool) -> Generator.Element? {
return lazy.filter(pred).first
}
}
Because:
#noescape can't be used because #noescape means that the closure cannot escape the current function, which would be possible when passing it to the lazy filter (doesn't evaluate elements until it is asked to -> has to escape the predicate)
throws can't be used because the filter is lazy -> errors wouldn't be thrown immediately, but rather when it is used the first time which would be when calling first, but first can't be throwing because it's a property. There are some discussions on making getters (and subscripts) throwing in future versions of Swift.
CollectionType has to be used, because only LazyCollectionType has the first property.
So to really make it lazy and have all the #noescape, throws and SequenceType, you'd have to use an imperative approach:
extension SequenceType {
func first(#noescape pred: Generator.Element throws -> Bool) rethrows -> Generator.Element? {
for elem in self where try pred(elem) {
return elem
}
return nil
}
}
In the simplest case, what you want may look like this:
let array = [18, 12, 35, 11, 12, 44]
var first: Int?
for element in array where element == 12 {
first = element
break
}
print(first) // prints: Optional(12)
If you really need to set a predicate closure, you can use the following pattern:
let array = [18, 12, 35, 11, 12, 44]
var first: Int?
let predicateClosure = { (value: Int) -> Bool in
return value == 12
}
for element in array where predicateClosure(element) {
first = element
break
}
print(first) // prints: Optional(12)
If you need to repeat these operations, you can refactor your code by using a SequenceType protocol extension:
extension SequenceType where Generator.Element == Int {
func getFirstWithPredicate(predicate: Int -> Bool) -> Int? {
for element in self where predicate(element) {
return element
}
return nil
}
}
let array = [18, 12, 35, 11, 12, 44]
let predicateClosure: Int -> Bool = {
return $0 == 12
}
let first = array.getFirstWithPredicate(predicateClosure)
print(first) // prints: Optional(12)
Note that you don't need your predicate closure parameter to escape your getFirstWithPredicate(_:) method here, so you can add the #noescape attribute before it (see Nonescaping Closures for more details):
extension SequenceType where Generator.Element == Int {
func getFirstWithPredicate(#noescape predicate: Int -> Bool) -> Int? {
for element in self where predicate(element) {
return element
}
return nil
}
}
let array = [18, 12, 35, 11, 12, 44]
let predicateClosure = { $0 == 12 }
let first = array.getFirstWithPredicate(predicateClosure)
print(first) // prints: Optional(12)
If you want the previous code to work for any type of sequence, you can remove the Int constraint and redeclare your getFirstWithPredicate(_:) method like in the following example:
extension SequenceType {
func getFirstWithPredicate(#noescape predicate: Generator.Element -> Bool) -> Generator.Element? {
for element in self where predicate(element) {
return element
}
return nil
}
}
let intArray = [18, 12, 35, 11, 12, 44]
let firstInt = intArray.getFirstWithPredicate { $0 == 12 }
print(firstInt) // prints: Optional(12)
let stringArray = ["Car", "Boat", "Plane", "Boat", "Bike"]
let firstString = stringArray.getFirstWithPredicate { $0 == "Boat" }
print(firstString) // prints: Optional("Boat")
If you're using a CollectionType protocol conforming object (for example, an Array), you can easily get the last element that matches your predicate with the same getFirstWithPredicate(_:) declaration by using reverse():
extension SequenceType {
func getFirstWithPredicate(#noescape predicate: Generator.Element -> Bool) -> Generator.Element? {
for element in self where predicate(element) {
return element
}
return nil
}
}
struct Toy {
let name: String
let price: Int
}
let array = [
Toy(name: "Ball", price: 20),
Toy(name: "Car", price: 12),
Toy(name: "Plane", price: 35),
Toy(name: "Boat", price: 12),
]
let lastToyWithMatchingPrice = array.reverse().getFirstWithPredicate { $0.price == 12 }
print(lastToyWithMatchingPrice) // prints: Optional(Toy(name: "Boat", price: 12))

Swift: Function returning an Array of IntegerType

I would like to create a function that takes an NSData parameter, and, depending on what it reads from the NSData it returns an Array<Int8>, Array<Int16>, Array<Int32>, or Array<Int64>.
Basically, I need to return an array of IntegerType, with the specific subtype being determined at runtime.
I am stuck at the signature declaration of the function. (The inside would just be a simple switch, that would create the specific array type and return it).
The following very basic test does not compile
class Test {
func test(data:NSData) -> Array<IntegerType> {
return [1, 2, 3]
}
}
EDIT
It seems to be currently not possible, not because of having to return an array of a protocol type, but because the IntegerType protocol uses Self. Here is an interesting related question
IntegerType is a protocol, so the following should work:
class Test {
func test(data:NSData) -> Array<T: IntegerType> {
[1, 2, 3]
}
}
You can use enum with associated values for that:
enum IntArray {
case Int8([Swift.Int8])
case Int16([Swift.Int16])
case Int32([Swift.Int32])
case Int64([Swift.Int64])
}
class Test {
func test(data:NSData) -> IntArray {
return IntArray.Int8([1, 2, 3]);
}
}
on user side:
let obj = Test()
let array = obj.test(dat)
switch array {
case .Int8(let ary):
// here, ary is [Int8]
...
case .Int16(let ary):
// here, ary is [Int16]
...
case .Int32(let ary):
// here, ary is [Int32]
...
case .Int64(let ary):
// here, ary is [Int64]
...
}
As others have said in the comments, this won't work if you are trying to determine the function's return type at runtime. Swift generics only work at compile time, so changing the return type based off of what's in an NSData won't work.
If you can determine the return type at compile time, then you can use a generic function declaration like so:
func test<T: IntegerType>(data: NSData) -> Array<T> {
return [1, 2, 3]
}
Note: If you don't specify the type explicitly in your function somehow, then you'll need to define the variable the value returned from the function is assigned to. Like so:
var int8Array: Array<Int8> = test(NSData())
Since none of the generic based solutions are working, why don't you try returning [Any] and just check the return type as follows:-
func test(data:NSData) -> [Any]
{
var value1:Int8 = 1
var value2:Int8 = 2
return [value1,value2]
}
var x = test(NSData())
for xin in x
{
var intxin = xin as? Int8
if intxin != nil
{
println(intxin!)
}
}
The way I solved my problem was by defining the following protocol:
protocol IntegerArrayProtocol {
init(rawData: NSData!, length: Int)
func count() -> Int
subscript(index:Int) -> Int { get }
}
This deals with all the operations I need to perform on the array:
Read it from raw memory
Count how many elements it has
Access its elements by index, always returning Ints, regardless of the underlying integer
type
Then, I created a parameterized class that implements the protocol:
final class IntegerArray<T: ConvertibleToInteger>: IntegerArrayProtocol {
let arr: [T]
init(rawData: NSData!, length: Int){
//create array and allocate memory for all elements
arr = Array<T>(count: length, repeatedValue: T.zero())
// read it from the NSData source
// ....
}
func count() -> Int{
return arr.count
}
subscript(index:Int) -> Int {
get {
return arr[index].asInt()
}
}
}
The parameter types T should be able to convert themselves to Int, and should have a zero value (used when I initialize the array). For that, I created the ConvertibleToInteger protocol, which is used above to restrict the possible Ts:
protocol ConvertibleToInteger {
class func zero() -> Self
func asInt() -> Int
}
Then, I extended every type that I would like to create arrays of:
extension Int8: ConvertibleToInteger{
static func zero() -> Int8{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int16: ConvertibleToInteger{
static func zero() -> Int16{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int32: ConvertibleToInteger{
static func zero() -> Int32{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int64: ConvertibleToInteger{
static func zero() -> Int64{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
Finally, to read an array from NSData, I created the following function:
func readArray(rawData: NSData, length: Int): IntegerArrayProtocol? {
qBytes = // read from NSData how many bytes each element is
switch(qBytes){
case 1:
return IntegerArray<Int8>(rawData: rawData, length: length)
case 2:
return IntegerArray<Int16>(rawData: rawData, length: length)
case 3 ... 4:
return IntegerArray<Int32>(rawData: rawData, length: length)
case 5 ... 8:
return IntegerArray<Int64>(rawData: rawData, length: length)
default:
return nil
}
}