Объединение данных в меньшие дискретные интервалы

Предположим, у нас есть пара входных массивов или список кортежей (ключ, значение), если хотите. Каков элегантный и эффективный способ объединения значений, индексы которых попадают в определенный интервал? Например, если размер интервала (или «бина») равен 10, тогда будут объединены значения всех индексов из 0 < x <= 10, а также значения индексов из 10 < x <= 20 и так далее. Я хочу:

let interval = 10
let index  = [| 6; 12; 18; 24 |]
let value  = [| a;  b;  c;  d |]
result = [| a; b + c; d |]

Самый грубый способ сделать это — использовать множество операторов if, else if (диапазон индекса имеет определенный верхний предел). я сблизился с

for i = 0 to index.Length do
    result.[Math.Floor(index.[i]/10] += value.[Math.Floor(index.[i]/10]

но это делает 0 <= x < 10, а не 0 < x <= 10.

Я также попытался предположить, что индексы упорядочены и равномерно распределены, с

for i = 1 : ( index.Length - 1 ) / valuesPerBin
    valueRange = ((i-1)*valuesPerBin + 1) : i*valuesPerBin )
    result(i) = sum(value(valueRange))

что хорошо, но, очевидно, ломается, если есть нецелое число значений в ячейке.

Как лучше всего это сделать на F#? Есть ли имя или существующая функция для того, что я пытаюсь сделать?


person arthuritus    schedule 01.02.2015    source источник
comment
Извините за внезапный переход от нотации F # array.[index] к нотации массива (index) MATLAB.   -  person arthuritus    schedule 01.02.2015
comment
Я отредактировал ваш заголовок. См. Должны ли вопросы включать «теги» в свои заголовки?, если нет единого мнения, не следует.   -  person John Saunders    schedule 01.02.2015


Ответы (2)


let interval = 10 
let index = [6;12;18;24] 
let value =[101;102;103;104] 
let intervals = List.map (fun e -> e/interval) index
let keys = List.map2(fun e1 e2 -> (e1,e2)) intervals value
let skeys = Seq.ofList keys
let result = skeys
             |>Seq.groupBy (fun p -> fst p) 
             |>Seq.map (fun p -> snd p)
             |>Seq.map(fun s -> Seq.sumBy (fun p -> snd p) s)

результат будет [101;205;104] (как последовательность).

Если вы хотите преобразовать в массив, примените Seq.toArray.

Это то, что ты хотел?

person FZed    schedule 01.02.2015

Адаптируйте окружающий код, чтобы использовать 0 <= x < 10 вместо 0 < x <= 10. В моем случае это было простое изменение определения в другой функции, что позволило мне использовать for i = 0 to index.Length do result.[Math.Floor(index.[i]/10] += value.[Math.Floor(index.[i]/10], который имеет более простой и лаконичный синтаксис, чем альтернативы.

person arthuritus    schedule 01.02.2015
comment
Хотя этот пример кода может ответить на вопрос, было бы предпочтительнее включить в ваш ответ некоторые важные пояснения. В нынешнем виде этот ответ практически не имеет ценности для будущих читателей. - person oɔɯǝɹ; 01.02.2015