Largest Even Number in an Array using Swift - 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()
}

Related

Getting error non-void return value in void function | Swift

I don't understand why I am getting the following error when executing this function:
error: unexpected non-void return value in void function
return [index, dic[value]!]
func findIndexes(_ nums: [Int], _ target: Int) -> [Int] {
var dic = [Int:Int]()
var answer: [Int] = []
nums.enumerated().forEach { index, value in
//the goal is to get the index of the value matching the difference
//check if current value == anything in dictionary
//MARK: Add the Index and Difference to Dictionary
let difference = (target - value)
if (dic.keys.contains(value) && !dic.values.contains(index)) {
return [index, dic[value]!]
}
dic[difference] = index
}
return []
}
print(findIndexes([0,11,15,2,7], 9))
I'm unclear what you're trying to do, but this is a version of what you are doing that compiles:
func findIndexes(_ nums: [Int], _ target: Int) -> [Int] {
var dic = [Int:Int]()
var answer: [Int] = []
for (index, value) in nums.enumerated() {
let difference = (target - value)
if (dic.keys.contains(value) && !dic.values.contains(index)) {
return [index, dic[value]!]
}
dic[difference] = index
}
return []
}
Why the difference? for...in is a loop. You can return from the surrounding function from within it, break out of it, etc. forEach loops implicitly but it is not a loop; it takes a closure, and you can't return out of that unless it's a closure that yields a return value, and this one doesn't; its type, as you can see from the docs, is (Self.Element) throws -> Void — and Void means "no return value".
If you insist on using forEach, you can do what you're trying to do with a bit of extra jiggery-pokery:
func findIndexes(_ nums: [Int], _ target: Int) -> [Int] {
var dic = [Int:Int]()
var answer: [Int] = []
nums.enumerated().forEach { index, value in
let difference = (target - value)
if (dic.keys.contains(value) && !dic.values.contains(index)) {
answer = [index, dic[value]!]
return
}
dic[difference] = index
}
return answer
}
I think that does what you're trying to do, but I'm not sure; it seems unnecessarily obscure. In my personal opinion, the way to program is to Say What You Mean (SWYM).

Cannot convert return expression of type Int to Int

I wonder why this is not work:
func removingOnce (_ item: Int, from array:[Int]) -> [Int]{
var intToReturn :Int?
intToReturn = 0
for ob in array5{
if (ob == item){
intToReturn = item
}
}
return intToReturn
}
It warn me with error: Cannot convert an expression of type Int to return type Int.
It make no sense at all
The warning reads
Cannot convert an expression of type Int to return type [Int]
and not as you stated it. (I tested it in Playground)
The reason for your error is that you return an Int value intToReturn, but according to the method definition, it should return an array of Ints ->[Int]
Either change the return value to the resulting Int array or change the return type in the method definition to ->Int?
Also, you declare intToReturn as an optional Int value. (Int?) but just after that, you assign it a value and it will not ever be nil. Rather do:
var intToReturn:Int = 0 or
var intToReturn = 0
Try this
[] menas array
func removingOnce (_ item: Int, from array:[Int]) -> Int{
var intToReturn :Int?
intToReturn = 0
for ob in array5{
if (ob == item){
intToReturn = item
}
}
return intToReturn
}
This is the best solution in my opinion to do this method:
func removingOnce (_ item: Int, from array:[Int]) -> Int? {
for ob in array {
if (ob == item){
return ob
}
}
return nil
}
The problem was the returning value. You wanted to return Int and in function you return an array of Ints.

What's the difference between `Int...` and `[Int]` in 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)

Elegant way to get the first n elements of a SequenceType

Is there an elegant way (think one-liner) to get the first n elements of a SequenceType in Swift?
I could of course write a for-loop that terminates after n elements but that's a little bulky.
Note also that the solution should be able to deal with infinite sequences.
Isn't it exactly what mySequence.prefix(numberOfElements) does?
In Swift 2, you can create this as an extension:
extension SequenceType {
func take(n: Int) -> [Generator.Element] {
var result: [Generator.Element] = []
var g = self.generate()
for _ in 1...n {
if let next = g.next() {
result.append(next)
} else {
break
}
}
return result
}
}
In Swift 1, it would have to written as a function:
func take<Seq: SequenceType>(n: Int, xs: Seq) -> [Seq.Generator.Element] {
var result: [Seq.Generator.Element] = []
var g = xs.generate()
for _ in 1...n {
if let next = g.next() {
result.append(next)
} else {
break
}
}
return result
}
Note that in either case, SequenceType does not specify what happens if you call generate() more than once. It could return the same values (as in an Array). It could return different values (as in an audio data stream). It could return nothing at all. So the caller of take() may need some special knowledge about its impact on the sequence.
SequenceType only supports generate(). Perhaps a more 'Swiftly' approach would be to define a Generator that given a start and end index and a 'base' generator would skip over the first elements, start returning some, and then stop after end index. Like this:
struct SubscriptGenerator<Base: GeneratorType> : GeneratorType {
var nowIndex : Int = 0
let endIndex : Int
let begIndex : Int
var generator : Base
init (generator: Base, startIndex: Int, endIndex: Int) {
precondition(startIndex < endIndex, "oops")
self.generator = generator
self.endIndex = endIndex
self.begIndex = startIndex
}
// MARK - GeneratorType
typealias Element = Base.Element
mutating func next() -> Element? {
while (nowIndex < begIndex) { nowIndex++; generator.next () }
return nowIndex++ < endIndex ? generator.next() : nil
}
}
This is only an example. One could define an convenience init() that takes a SequenceType and produces the base generator. In action:
75> var gen = [10,20,30,40,50].generate()
76> var sg = SubscriptGenerator(generator: gen, startIndex: 1, endIndex:3)
sg: SubscriptGenerator<IndexingGenerator<[Int]>> = { ... }
77> sg.next()
$R2: Int? = 20
78> sg.next()
$R3: Int? = 30
79> sg.next()
$R4: Int? = nil
See Swift's EnumerateGenerator for an example.
Note: it might be the Stride nexus of Swift functionality does what you want already.
Why not
var seq = NominalSequence().generate()
var a = (0..<10).map({_ in seq.next()!})
?
Two lines, but funtional-ish.

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
}
}