Swift 感受“爱”;“需要速度”;使用reduce(into::)对三元组元素集的封闭数组中的元素进行计数

Swift 感受“爱”;“需要速度”;使用reduce(into::)对三元组元素集的封闭数组中的元素进行计数,swift,block,reduce,counting,Swift,Block,Reduce,Counting,鉴于这个三元组的示例数组,实际数组将是非常大的数据集,因此“需要速度”: 在保留三元组的同时,使用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]

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

在保留三元组的同时,使用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:u:)解决,但我无法正确地“计算”元素。我将代码保留在其中,它不能正确计算,显然是因为每次都初始化了,但我想展示我到目前为止所拥有的:

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...
]
非常感谢您的见解

两个步骤:

  • 将数组展平,只需为所有值制作一个普通的直方图(计数)(这是一条直线)

  • 现在回到原始数组并将其映射到成对数组中

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

    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)]]
    

    这是正确的。

    实际上似乎很简单。首先,将数组展平,只需为所有值制作一个普通的直方图(计数)(这是一条直线)。然后返回原始数组并将其映射到成对数组中。我希望在一个块内完成此操作,因为这似乎是reduce能做得最好的,直方图确实很容易,但在一个块内保持三元组顺序很困难。我真的不知道“在一个块中”是什么或者,如果您愿意,尽可能少的循环/函数/分支,它感觉像reduce(into):可以用很少的“额外”来实现这一点干预,我当然可能是错的。@LeoDabus是的,我调整的重点是,我看不到只有一个条目的字典的值。只是没有目的的大量开销。感谢这个两步过程,而且可能确实不可能在一个简化中完成(into:block。我觉得这是可能的,所以我会等着看是否有人能展示一个reduce(into:function)(或者什么函数),速度方面会更好,因为我会在海量数据集上使用它。我会在我的问题标题“reduce(into)”中添加“对速度的需求”:当然,这很公平。在上面的代码中,每次我都有一个左大括号,这就是一个循环。但请注意,我不知道如何减少循环的数量,因为在开始处理问题时,您必须已经知道直方图计数。如果不知道,那么每次遇到已使用的元素和nge所有提到的元素的数量都是指数级的。因此,我认为我的方法是快速方法,而你的
    reduce(into:)
    spec是一个麻烦(也称为x-y问题)。
    [[(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)]]