【问题标题】:Swift - Group elements of Array by value (2 by 2, 3 by 3, etc...)Swift - 按值对 Array 的元素进行分组(2 乘 2、3 乘 3 等...)
【发布时间】:2019-06-26 22:09:30
【问题描述】:

编辑:我不是要求函数来计算出现次数。我要求一个函数来计数 2 乘 23 乘 310 乘 10 等...这是我的问题

我有一个分数数组,比如说:

[2,2,3,4,4,4,4,5,6,6,8,8,8,9,10,10]

我想要一个函数将这个 Array 转换为 Dictionary [Int: Int]() 以获得类似的东西:

func groupArrayBy(array: Array<Int>, coef: Int) -> Array<Int, Int>{
   // if coef = 2 -> 2 by 2, count occurence
   // Transform the array to:
   // [2: 3, 4: 5, 6: 2, 8: 4, 10: 2]
   // return Dictionary
}

(如果 coef = 3,则为:[2: 7, 5: 3, 8: 6] -> 3 x 3)

我对此一无所知。甚至可能吗?

【问题讨论】:

  • 我已将其作为副本关闭。对系数的要求只是对所有内容进行计数的简单扩展(计算出现次数,然后过滤结果以获取值 > 系数)。
  • 感谢您的回答,但即使对您来说看起来很简单,我也在这部分苦苦挣扎了好几个小时。我是否必须为此重新提出一个新问题?我试图调整功能但没有成功
  • @Sulthan,我认为这个要求不够简单,以至于被标记为重复。
  • @Sulthan 不幸的是,此代码无法正常工作
  • 看来我不确定系数的实际含义。你能详细说明一下吗?

标签: ios arrays swift sorting swift3


【解决方案1】:

这是我的版本,我根据数组的第一个值和coef 变量对范围进行过滤,根据结果,我切掉那些已经计算过的元素,然后在循环中的较小数组上再次过滤。该方案要求输入数组按升序排序

func group(_ array: [Int], coef: Int) -> [Int: Int] {
    var result:[Int:Int] = [:]

    var start = array[0]
    var end = start + coef - 1
    var arr  = array

    while start <= array[array.count - 1] {
       let count = arr.filter({ $0 >= start && $0 <= end}).count

       result[start] = count
       start = end + 1
       end = start + coef - 1
       arr = Array(arr[count...])
    }
    return result
}

这是上述函数的递归版本

func group(_ array: [Int], coef: Int) -> [Int: Int] {
    var result:[Int:Int] = [:]
    if array.isEmpty { return result }

    let end = array[0] + coef - 1
    let count = array.filter({ $0 >= array[0] && $0 <= end}).count
    result[array[0]] = count
    result = result.merging(group(Array(array[count...]), coef: coef)) { $1 }
    return result
}

【讨论】:

  • filter(predicate).count 是一种反模式。它分配一个中间数组并复制所有传递的元素,只是为了计算它们立即丢弃它们。请改用.count(where: predicate)
  • @Alexander 那么我猜 Swift 是一种反模式,至少在我写这个答案的时候是这样,因为当时不存在 count(where:) 并且我不确定它是否存在。介意给我一些文档吗?
  • 哦,我想this was shipped already, but it's only been implemented。 (我的项目中有一个做同样事情的扩展)。没关系,那么您可以求助于之前的最佳实践,array.lazy.filter(predicate).count
【解决方案2】:

我对系数仍然有些困惑。但是,假设您想要将任何值 N 与下一个 N+coefficient 值组合在一起。

然后我将首先将原始数组重新映射到组值:

let items = [2,2,3,4,4,4,4,5,6,6,8,8,8,9,10,10]

let uniqueItems = Set(items)
var itemCoefficientMapping: [Int: Int] = [:]

let coefficient = 3
for item in uniqueItems.sorted() {
    // look whether exists some lower value that is not itself mapped to another value
    let normalizedItem = (item - (coefficient - 1)...item).first {
        uniqueItems.contains($0) && itemCoefficientMapping[$0] == $0
    } ?? item
    itemCoefficientMapping[item] = normalizedItem
}

// count  by mapped value
let counts: [Int: Int] = items.reduce(into: [:]) { result, value in
    result[itemCoefficientMapping[value] ?? value, default: 0] += 1
}

print(counts)

【讨论】:

  • 完美,这就是我想要的,谢谢。很抱歉造成混乱
【解决方案3】:

您的问题是如此令人困惑,以至于coef 的含义或我们可以期望输入数组已排序,您想要什么输出类型。 Swift 中没有 Array&lt;Int, Int&gt;

假设输入数组已排序并且你想要Array&lt;(Int, Int)&gt;,你可以这样写:

func getRanges(_ arr: [Int], _ step: Int) -> [Range<Int>] {
    return stride(from: arr.first!, through: arr.last!, by: step)
        .map {$0..<$0+step}
}
func groupArrayBy(array: Array<Int>, coef: Int) -> [(Int, Int)] {
    let grpArr = getRanges(arr, coef).map {rng in
        (rng.lowerBound, arr.lazy.filter{rng.contains($0)}.count)
    }
    return grpArr
}

print(groupArrayBy(array: arr, coef: 2)) //->[(2, 3), (4, 5), (6, 2), (8, 4), (10, 2)]
print(groupArrayBy(array: arr, coef: 3)) //->[(2, 7), (5, 3), (8, 6)]

我的代码效率不高,可能有人可以向您展示更高效的代码。

【讨论】:

    【解决方案4】:

    它可能有另一个更简单的代码:

    let aa : [Int] = [2,2,3,4,4,4,4,5,6,6,8,8,8,9,10,10]
    let mini = aa.min()!
    let coeff : Int = 3
    
    let dict = Dictionary(grouping: aa) {
    mini + (($0 - mini) / coeff) * coeff
       }.mapValues{$0.count}
    
    print (dict)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-10
      • 2019-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多