2016-04-13 13 views
3

ネストされたリストのすべての番号がグループ化されているgroupBy機能を実装しようとしています。これまでの私のコード:Swiftのキーによるグループ辞書

struct MyClass { 
    var numbers: [Int] 
    ... 
} 

var dict: [String : MyClass] = ... 
let numbers = dict 
    .filter{ $0.0.containsString(searchString) } 
    .flatMap{ $0.1.numbers } 

これは私Int秒のArrayを生成します。しかし、私はそれぞれのユニークな数とその出現の数で辞書[Int:Int]を持っていたいと思います。だから、例えば:

[1,2,3,4,1,2,2,1] 

は次のようになります。

[1 : 2, 2 : 3, 3 : 1, 4 : 1] 

私はgroupByオペレータがあります知っているが、スウィフトは1を持っていないようです。私はreduceで試してみた:

func reducer(accumulator: [Int: Int], num: Int) -> [Int : Int] { 
    var acc = accumulator 
    acc[num]! += 1 
    return acc 
} 

filtered.reduce([:], combine: reducer) 

しかし、私はそれを実行したいときにクラッシュします。理由は分かりませんが、EXC_BAD_INSTRUCTIONが表示されます。

ご協力いただきありがとうございます。

+0

UPSは、ええ、辞書を意味しました。 – SamW

+0

コードをコピーして貼り付けることができれば助かります。 – ryantxr

+0

コピーして貼り付けたらどういう意味ですか? – SamW

答えて

3
let numbers = [1,2,3,4,1,2,2,1] 
var results = [Int: Int]() 

Set(numbers).forEach { number in results[number] = numbers.filter { $0 == number }.count } 

print(results) // [2: 3, 3: 1, 1: 3, 4: 1] 

実際に私はこれがあなたが望むものなのかどうかは分かりません。私はあなたの例を見ました。使用

NSCountedSet

var objects = [1,2,3,4,1,2,2,1] 
let uniques = NSCountedSet(array: objects) 
uniques.forEach { results[$0 as! Int] = uniques.countForObject($0) } 

print(results) // [2: 3, 3: 1, 1: 3, 4: 1] 
+0

これは素晴らしいです。 – ryantxr

3

私はクラッシュが、このライン上ocurringすることが期待される:

acc[num]! += 1 

これは数のために初めて呼び出されたときに、エントリがacc[num]nilで、まだそれほど辞書には存在しません。それを強制的にアンラッピングするとクラッシュが発生します。これが最善の解決策であるが、場合

わからないことができます。この場合の簡単なチェック:コメント欄で@vacawamaから

if (acc[num]) { 
    acc[num]! += 1 
} else { 
    acc[num] = 1 
} 

クリーナーコード:

acc[num] = (acc[num] ?? 0) + 1 
+0

これは、感謝しました。悲しいことに私はまだupvoteすることはできません – SamW

+0

@スウォーカーは問題ではない、私は助けることができてうれしい。 :]へようこそ! – Jack

+4

'acc [num] =(acc [num] ?? 0)+1 ' – vacawama

0

あなたはこのような何かが必要になります。

if let _ = acc.indexForKey(num) { 
    acc[num]! += 1 
} 
else { 
    acc[num] = 1 
} 
0

それは一種の不明確あなたが求めているものだが、ここではintの配列を取得し、キーとして番号と辞書を返す関数だ、と数値として:

func getDictionaryOfCounts(accumulator: [Int]) -> [Int : Int] { 
    var countingDictionary: [Int : Int] = [:] 
    accumulator.forEach { (value) in 
     if countingDictionary[value] != nil { 
      countingDictionary[value]! += 1 
     } 
     else{ 
      countingDictionary[value] = 1 
     } 
    } 
    return countingDictionary 
} 
2

は、ここであなたが求めているものをしたアレイへの拡張です:

extension Array where Element: Hashable { 
    var grouped: [Element:Int] { 
    var dict = [Element:Int]() 
    self.forEach { dict[$0] = (dict[$0] ?? 0) + 1 } 
    return dict 
    } 
} 

鍵はクロージャー:{ dict[$0] = (dict[$0] ?? 0) + 1 }です。

配列の現在の値を受け取り、辞書の中のキーであるかどうかを調べ、存在する場合はそのキーの値を返し、存在しない場合は0を返し、1を加えてキーを設定します。valueこれまでの現行値と現行のペアとなります。

使用例:

[1,2,3,4,1,2,2,1].grouped // => [2: 3, 3: 1, 1: 3, 4: 1] 
関連する問題