首页 > 解决方案 > 感受“对速度的需求” 使用 reduce(into:_:) 计算封闭数组中的三元组元素

问题描述

鉴于此示例数组三元组,实际数组将是非常大的数据集,因此“需要速度”:

let usedIndicies2 = [
    [0, 1, 2]
    [2, 1, 3],
    [1, 4, 3],
    [3, 4, 5],
    [6, 7, 8],
    [8, 7, 9],
    [7, 10, 9],
    [9, 10, 11],
    [12, 2, 13],
    [13, 2, 14],
    [2, 3, 14],
    [14, 3, 15],
    [3, 5, 15],
    [15, 5, 16],
    [5, 17, 16],
    [16, 17, 18],
    [19, 8, 20],
    [20, 8, 21],
    [8, 9, 21],
    [21, 9, 22],
    [9, 11, 22],
    [22, 11, 23],
    [11, 24, 23],
    [23, 24, 25],
    [13, 14, 26],
    [26, 14, 27],
    [14, 15, 27],
    [27, 15, 28],
    [15, 16, 28],
    [28, 16, 29],
    [16, 18, 29],
    [29, 18, 30],
    [18, 20, 30],
    [30, 20, 31],
    [20, 21, 31],
    [31, 21, 32],
    [21, 22, 32],
    [32, 22, 33],
    [22, 23, 33],
    [33, 23, 34],
    [26, 27, 35],
    [35, 27, 36],
    [27, 28, 36],
    [36, 28, 37],
    [28, 29, 37],
    [37, 29, 38],
    [29, 30, 38],
    [38, 30, 39],
    [30, 31, 39],
    [39, 31, 40],
    [31, 32, 40],
    [40, 32, 41],
    [32, 33, 41],
    [41, 33, 42],
    [33, 34, 42],
    [42, 34, 43],
    [44, 35, 45],
    [45, 35, 46],
    [35, 36, 46],
    [46, 36, 47],
    [36, 37, 47],
    [47, 37, 48],
    [37, 38, 48],
    [48, 38, 49],
    [38, 39, 49],
    [49, 39, 50],
    [39, 40, 50],
    [50, 40, 51],
    [40, 41, 51],
    [51, 41, 52],
    [41, 42, 52],
    [52, 42, 53],
    [42, 43, 53],
    [53, 43, 54],
    [43, 55, 54],
    [54, 55, 56],
]

使用 swift查找此类数组的每个元素的计数,同时保留三元组,因此输出如下所示:

let keyValuePairs =[
  [[0: 1], [1: 3], [2: 5]],
  [[2: 5], [1: 3], [3: 6]],
  [[1: 3], [4: 2], [3: 6]],
  [[3: 6], [4: 2], [5: 4]],
  [[6: 1], [7: 3], [8: 5]],
  [[8: 5], [7: 3], [9: 6]],
  [[7: 3], [10: 2], [9: 6]],
  [[9: 6], [10: 2], [11: 4]],
  // etc. ...
]

我只是建议“减少(进入”),因为它感觉是可能的,但它可能完全是更好/更快/更强的其他东西。

(不必保留三元组的顺序但必须保留三元组中元素的顺序:例如第一个和第二个需要保持 [[0:x], [1:x], [2: x]]、[[2:x]、[1:x]、[3:x]],或者作为示例,顺序可以是 [[2:x]、[1:x]、[3:x]] , [[0:x], [1:x], [2:x]] 代替。

到目前为止,我已经能够使用下面的代码生成正确的组织,感觉这可以通过 reduce(into:_:) 解决,但我无法正确“计算”元素。我已经离开了其中的代码计算不正确,显然是因为它每次都被初始化,但想展示我到目前为止的内容:

let keyValuePairs = usedIndicies2.reduce(into: [[[UInt32:Int]]]()) { (array, entry) in

    var dict0:[UInt32:Int] = [UInt32:Int]()
    var dict1:[UInt32:Int] = [UInt32:Int]()
    var dict2:[UInt32:Int] = [UInt32:Int]()

    dict0[entry[0], default: 0] += 1
    dict1[entry[1], default: 0] += 1
    dict2[entry[2], default: 0] += 1

    var array012:[[UInt32:Int]] = [[UInt32:Int]]()

    array012.append(dict0)
    array012.append(dict1)
    array012.append(dict2)

    array.append(array012)
}

print("keyValuePairs:",keyValuePairs)

此部分工作代码的输出如下所示

let keyValuePairs** = [
    [[0: 1], [1: 1], [2: 1]],
    [[2: 1], [1: 1], [3: 1]],
    [[1: 1], [4: 1], [3: 1]],
    [[3: 1], [4: 1], [5: 1]],
    [[6: 1], [7: 1], [8: 1]],
    [[8: 1], [7: 1], [9: 1]],
    [[7: 1], [10: 1], [9: 1]],
    [[9: 1], [10: 1], [11: 1]],
    // etc...
]

非常感谢您的见解

标签: swiftblockreducecounting

解决方案


两步:

  1. 展平数组并为所有值制作一个普通的直方图(计数)(这是一个单行)。

  2. 现在回到原始数组并将其映射到对数组中。

为了演示,我将只对您的数据的开头部分进行操作,以证明它有效。我已经对键值对的概念给出了自己的解释(我使用了带有标签的元组),但可以根据需要随意修补。

let original = [[0, 1, 2], [2, 1, 3], [1, 4, 3], [3, 4, 5]]
// step 1
var histo = [Int:Int]()
original.flatMap {$0}.forEach {histo[$0, default:0] += 1}
// step 2
let output = original.map {array in array.map {i in (item:i, count:histo[i]!)}}

结果:

[[(item: 0, count: 1), (item: 1, count: 3), (item: 2, count: 2)], 
 [(item: 2, count: 2), (item: 1, count: 3), (item: 3, count: 3)], 
 [(item: 1, count: 3), (item: 4, count: 2), (item: 3, count: 3)], 
 [(item: 3, count: 3), (item: 4, count: 2), (item: 5, count: 1)]]

这是正确的。


推荐阅读