Swift - группирует элементы массива по значению (2 на 2, 3 на 3 и т. Д.) - PullRequest
0 голосов
/ 02 февраля 2019

РЕДАКТИРОВАТЬ: я не прошу функцию для подсчета случаев.Я прошу функцию подсчитать вхождение 2 на 2 , 3 на 3 , 10 на 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 на 3)

Я ничего не нашел по этому поводу.Это вообще возможно?

Ответы [ 4 ]

0 голосов
/ 02 февраля 2019

Может иметь другой, более простой код:

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)
0 голосов
/ 02 февраля 2019

Я все еще немного озадачен коэффициентом.Однако, давайте предположим, что вам нужно сгруппировать любое значение 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)
0 голосов
/ 02 февраля 2019

Вот моя версия, в которой я фильтрую диапазон, основываясь на первом значении массива и переменной 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
}
0 голосов
/ 02 февраля 2019

Ваш вопрос настолько сбивает с толку, что означает coef или мы можем ожидать, что входной массив отсортирован, какой тип вывода вы хотите.В Swift нет Array<Int, Int>.

Предполагая, что входной массив отсортирован и вам нужно Array<(Int, Int)>, вы можете написать что-то вроде этого:

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

Мой код не так эффективен иможет быть, кто-то может показать вам более эффективный код.

...