0

I want to count the individual elements in the following array:

let b = [
    1, 2, 3,
    [4,5,6],
    [
        [7,8],
        [9,0]
    ]
]

, and I was able to count the following array:

let a = [
    [1,2,3],
    [4,5],
    [6,7,8,9]
]

with the following code:

protocol DeepCountable {
    var deepCount: Int {get}
}

// conditional conformance
extension Array: DeepCountable where Element: DeepCountable {
    var deepCount: Int {
        return self.reduce(0){$0 + $1.deepCount}
    }
}

extension Int: DeepCountable {
    var deepCount: Int { return 1 }
}

print(a.deepCount)      // 9

How do I do the same thing to array b?

print( b.deepCount )
lochiwei
  • 1,240
  • 9
  • 16

4 Answers4

2

Type of array b is [Any]. Any isn't DeepCountable. Now add a deepcount property in Array

extension Array: DeepCountable {
    var deepCount: Int {
        return self.compactMap({ $0 as? DeepCountable }).reduce(0, { $0 + $1.deepCount })
    }
}

let a = [[1,2,3],[4,5],[6,7,8,9]]
print(a.deepCount)//9
let b = [1, 2, 3,[4,5,6],[[7,8],[9,0]]] as [Any]
print(b.deepCount)//10
let c = [1,2,"a","b"] as [Any]
print(c.deepCount)//2
RajeshKumar R
  • 15,445
  • 2
  • 38
  • 70
1

Here is a generic solution that can count different types

extension Array {
    func countType<T>(_ elemType: T.Type) -> Int {
        var count = 0
        for elem in self {            
            if let _ = elem as? T {
                count += 1
            } else if let arr = elem as? [Any] {
                count += arr.countType(elemType)
            }
        }
        return count
    }
}

Usage

let b = [1, 2, 3,[4,5,6],[[7,8],[9,0]]] as [Any]
let c = [1,2,"a","b"] as [Any]

print("Int Count    \(b.countType(Int.self))")
print("Array Count  \(b.countType([Int].self))")
print("Int Count    \(c.countType(Int.self))")
print("String Count \(c.countType(String.self))")
print("Array Count  \(c.countType([Int].self))")

yields

Int Count    10  
Array Count  3  
Int Count    2  
String Count 2  
Array Count  0
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
0

Firstly you need to flatten the array into single then count that array.

let b = [
    1, 2, 3,
    [4,5,6],
    [
        [7,8],
        [9,0]
    ]
]
let flatb = b.flatMap({ $0 })
print(flatb.count)
Zeeshan Ahmed
  • 834
  • 8
  • 13
0

The following code is the result I concluded from the above contributions:

protocol DeepCountable {
  var deepCount: Int { get }
}

// now any Array is DeepCountable
extension Array: DeepCountable {
  var deepCount: Int {
    return compactMap{ $0 as? DeepCountable }.reduce(0){ $0 + $1.deepCount }
  }
}

extension Int: DeepCountable {
  var deepCount: Int { return 1 }
}

// test
let a = [[1,2,3],[4,5],[6,7,8,9]]
let b = [1, 2, 3,[4,5,6],[[7,8],[9,0]]] as [Any]
let c = [1,2,"a","b"] as [Any]
let d = [1,2,3,[4,5],[6,7,8,[9, 0]]] as [Any]

print( a.deepCount )  //  9
print( b.deepCount )  // 10
print( c.deepCount )  //  2
print( d.deepCount )  // 10

This code should work with Swift 5, I've tried it on Online Swfit Playground, and it works fine.

lochiwei
  • 1,240
  • 9
  • 16
  • Instead of using a computed property you should use a throwable function if you want to throw error for invalid arrays like [1,2,"a","b"] – RajeshKumar R Apr 10 '19 at 11:54