Проблемы со сгибом в Rust

Предположим, fn scan(int, int) -> int.

Когда используешь

fn count(x: int, y: int) -> int
{
    scan(x - 1, y - 1) + scan(x - 1, y) + scan(x - 1, y + 1) + scan(x, y - 1)
        + scan(x, y + 1) + scan(x + 1, y - 1) + scan(x + 1, y) + scan(x + 1, y + 1)
}

Я получаю правильные результаты. Я пытаюсь получить те же результаты, fold используя функцию scan в заданных диапазонах значений; однако я не могу понять это правильно. Моя текущая попытка

fn count_fold(x: int, y: int) -> int
{
    std::iter::range_inclusive(-1, 1).zip(std::iter::range_inclusive(-1, 1)).fold(0, |a, (i, j)| { a + scan(x + i, y + j) })
}

который, кажется, возвращает только подмножество правильных результатов. Что я делаю не так? ТИА.


person Arets Paeglis    schedule 06.12.2013    source источник


Ответы (2)


Когда вы запаковываете два итератора, вы не создаете "продукт" итераций, как вы, кажется, хотите сделать. Скорее, вы выполняете итерацию обоих итераторов одновременно и создаете пару с повторяемыми значениями. Таким образом, в версии count_fold замыкание будет вызываться только со следующими парами:

(-1, -1)
(0, 0)
(1, 1)

Итак, ваша функция count_fold на самом деле похожа на

scan(x - 1, y - 1) + scan(x, y) + scan(x - 1, y + 1)

Я могу ошибаться, но я не думаю, что в std есть функция, создающая произведение двух итераторов.

Более того, ваш метод count не использует scan(x, y) в сумме, так что это даже не продукт итераторов; вы должны быть осторожны с этим, если хотите создать свой собственный итератор продукта и использовать его для этой цели.

person Cyrille Ka    schedule 06.12.2013
comment
Чтобы немного прояснить ситуацию, мне не нужно scan(x, y). Идея состоит в том, чтобы сканировать [так в оригинале] окрестности Мура с заданными координатами. - person Arets Paeglis; 07.12.2013

Кирилл прав, говоря, что нет функции итератора-произведения. Однако можно вручную взять произведение двух итераторов, свернув дважды:

use std::iter::range_inclusive;

fn count_fold(x: int, y: int) -> int {
    range_inclusive(-1, 1).fold(0, 
         |a, i| range_inclusive(-1, 1).fold(a, |b, j| b + scan(x + i, y + j)))
}

Хотя, похоже, вам нужно отфильтровать случай, когда i == 0 && j == 0, т.е.

fn count_fold(x: int, y: int) -> int {
    range_inclusive(-1, 1).fold(0, 
         |a, i| range_inclusive(-1, 1).fold(a, 
             |b, j| if i == 0 && j == 0 {b} else {b + scan(x + i, y + j)}))
}

or

fn count_fold(x: int, y: int) -> int {
    range_inclusive(-1, 1).fold(0, 
         |a, i| range_inclusive(-1, 1)
             .filter(|&j| !(i == 0 && j == 0))
             .fold(a, |b, j| b + scan(x + i, y + j)))
}

Однако я бы почти сказал, что это яснее повелительно:

fn count_fold(x: int, y: int) -> int {
    let mut a = 0;
    for i in range_inclusive(-1, 1) {
        for j in range_inclusive(-1, 1) {
            if !(i == 0 && j == 0) { a += scan(x + i, y + j) }
        }
    }
    a
}
person huon    schedule 07.12.2013
comment
Это странно. Ваша императивная версия, как и моя, дает правильные результаты, но ваша функциональная версия не работает (также scan фильтрует случаи, когда i == 0 && j == 0 поэтому count этого делать не нужно). - person Arets Paeglis; 10.12.2013