问题
EDIT: I'm not asking a function to count an occurence. I'm asking a function to count an occurence 2 by 2, 3 by 3, 10 by 10, etc... this is my problem
I have an array of scores, lets say:
[2,2,3,4,4,4,4,5,6,6,8,8,8,9,10,10]
I would like to have a function that transform this Array into a Dictionary [Int: Int]() to have something like that:
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
}
(With coef = 3, it would be: [2: 7, 5: 3, 8: 6] -> 3 by 3)
I found nothing about that. Is it even possible ?
回答1:
Here is my version where I filter on a range based on first value of the array and the coef variable, based on the result I slice away those elements already counted and filter again on the smaller array in a loop. This solution requires the input array to be sorted in ascending order
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
}
And here is a recursive version of the above function
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
}
回答2:
I am still a bit confused about the coefficient. However, let's suppose that what you want is to group any value N with the next N+coefficient values.
Then I would start by remapping the original array into the group values:
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:
Your question is so confusing that what coef means or can we expect the input array is sorted, what output type you want. There's no Array<Int, Int> in Swift.
Assuming the input array is sorted and you want Array<(Int, Int)>, you can write something like this:
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)]
My code is not so efficient and there may be someone who can show you more efficient code.
回答4:
It may have another simpler code as this:
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)
来源:https://stackoverflow.com/questions/54494620/swift-group-elements-of-array-by-value-2-by-2-3-by-3-etc