Конкатенация возвращает больше элементов, чем должно

Мне нужно получить соседей ячеек на 1D замкнутом поле

Например:

соседи [1,2,3,4,5,-1] (6 элементов)

должен вернуть [[-1,1,2],[1,2,3],[2,3,4],[3,4,5],[4,5,-1],[5,-1 ,1]] (6 элементов)

мой код соседей

neighbours :: [a] -> [[a]]
neighbours l = concat [[[last l, head l, last $ take 2 l]], neighbours' l, [[l !! (length l - 2), last l, head l]]] where
    neighbours' :: [a] -> [[a]]
    neighbours' (a:b:c:xs) = [a, b, c]:neighbours (b:c:xs)
    neighbours' _ = []

main = print $ neighbours [1, 2, 3, 4]

возвращает [[4,1,2],[1,2,3],[4,2,3],[2,3,4],[4,3,4],[3,4,3], [3,4,2],[3,4,1]] (8 элементов), но ожидается [[4,1,2],[1,2,3],[2,3,4],[3 ,4,1]] (4 элемента)

если я прокомментирую соседей, я вернусь [[4,1,2],[3,4,1]] как и ожидалось (2 элемента)

если ты оставишь только соседей, я вернусь [[1,2,3],[2,3,4]] как и ожидалось (2 элемента)

2+2=4, но в данном случае почему-то 8

почему это происходит?

P.S.

соседи создать середину списка

соседи' [1,2,3,4,5,-1] == [[1,2,3],[2,3,4],[3,4,5],[4,5,-1 ]]

[последняя л, голова л, последняя $ взять 2 л] создать начало списка [-1,1,2]

[л!! (length l - 2), last l, head l] создать последний элемент списка [5,-1,1]

Ваш код довольно загадочен, потому что вы не дали никакого контекста о том, что он должен иметь в виду. Пожалуйста, объясните в теле вашего вопроса. Использование head, last и !! еще больше затрудняет угадывание ваших намерений.

dfeuer 20.03.2022 09:03

Желаемый результат можно получить так: neighbors xs = let k = length xs in (drop (k-1) $ take (k+k-1) $ map (take 3) (tails (cycle xs)))

jpmarinier 20.03.2022 09:08

@dfeuer я добавил информацию о целях кода и его компонентов

N0lim 20.03.2022 09:51
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш код несколько сложен для понимания, потому что две ваши функции, neighbour и neighbour', являются рекурсивными взаимно, что довольно необычно.

Ключевая строка в вашем коде:

neighbours' (a:b:c:xs) = [a, b, c] : neighbours (b:c:xs)

Если предположить, что это НЕТ преднамеренно, и вы просто хотели написать:

neighbours' (a:b:c:xs) = [a, b, c] : neighbours' (b:c:xs)
-----------------------------------------------+---------

тогда код работает так, как вы ожидаете.

Обратите внимание, что наличие длинных (более 80 символов) строк кода сильно затрудняет отладку.

Предлагаемый код:

{-#  LANGUAGE  ScopedTypeVariables  #-}
{-#  LANGUAGE  ExplicitForAll       #-}

import qualified  Data.List  as  L

neighbours :: [a] -> [[a]]
neighbours l = concat [
                         [[last l, head l, last $ take 2 l]],
                         neighbours' l,
                         [[l !! (length l - 2), last l, head l]]
                      ]
  where
    neighbours' :: [a] -> [[a]]
    neighbours' (a:b:c:xs) = [a, b, c] : neighbours' (b:c:xs)
    neighbours' _ = []


-- neighbour is British English, neighbor is US English
neighbors :: [a] -> [[a]]
neighbors xs =
    take count $ drop  (count-1)  allTriplets  -- section of infinite list
      where
        count        =  length xs
        allTriplets  =  map  (take 3)  (L.tails (cycle xs))  -- raw material


main :: IO ()
main = do
    print $ "res1 = " ++ (show $ neighbours [1, 2, 3, 4])
    print $ "res2 = " ++ (show $ neighbors  [1, 2, 3, 4])

Вывод программы:

"res1 = [[4,1,2],[1,2,3],[2,3,4],[3,4,1]]"
"res2 = [[4,1,2],[1,2,3],[2,3,4],[3,4,1]]"

Я думаю, что вы можете сделать это проще без tails. zip3 (drop (count-1) cycled) xs (drop 1 cycled)

dfeuer 20.03.2022 17:03

Что ж, tails относительно дешево, но идея хорошая, спасибо. Просто нужно преобразовать кортеж в список в конце.

jpmarinier 20.03.2022 19:40

Это был просто набросок. На самом деле вы бы использовали zipWith3 (\a b c -> [a,b,c]).

dfeuer 20.03.2022 23:04

Другие вопросы по теме