Elm - обновить элементы в списке

Я только начал программировать в Elm и кое-что застрял:

Я хотел бы иметь метод, который может обновлять поля элементов в списке по определенному индексу.

Моя подпись будет выглядеть так:

updateElement : List (ID, Task) -> Int -> List (ID, Task)

с:

type alias Task =
  { description : String, focus : Bool}

В этом случае я хотел бы установить логическое значение (фокус) задачи по индексу, заданному как true, а всем остальным задачам в списке — как false.

Я уже пробовал работать с массивами в Elm, но тогда мне приходится работать с Maybe, и я не думаю, что это хорошее решение.

Я предполагаю, что мне придется работать с «картой», чтобы изменить элементы в моем списке, но я понятия не имею, как я могу изменить ее по определенному индексу.

Спасибо!


person Thibault    schedule 29.12.2015    source источник
comment
Вы имели в виду List (Int, Task) -> Int -> List (Int, Task)? Или List (ID, Task) -> ID -> List (ID, Task) где type alias ID = Int?   -  person robertjlooby    schedule 29.12.2015
comment
Также Task, вероятно, плохой выбор для имени, так как уже есть Задача в основном пакете   -  person robertjlooby    schedule 29.12.2015
comment
Да, действительно, моя ошибка. Подпись должна быть updateElement: List (ID, Task) -> Int -> List (ID, Task), где я хочу изменить n-й элемент списка   -  person Thibault    schedule 29.12.2015


Ответы (3)


Теперь, когда вы уточнили свой вопрос, настоящий ответ представляет собой комбинацию двух обновлений, опубликованных Чадом.

updateElement : List (ID, Task) -> Int -> List (ID, Task)
updateElement list indexToFocusOn =
  let
    toggle index (id, task) =
      if index == indexToFocusOn then
        (id, { task | focus = true })
      else
        (id, { task | focus = false })
  in
    List.indexedMap toggle list
person robertjlooby    schedule 29.12.2015

Если вы хотите часто изменять только n-й элемент списка, List будет неправильной структурой данных. List в elm реализован как связанный список, который не будет хорошо работать с точки зрения производительности при произвольном доступе.

Для такой работы вам, вероятно, лучше использовать массив elm Array, и действительно, у массива есть простая функция для установки n-го элемента, оставляя все остальные нетронутыми: Array.set :: Int -> a -> Array a -> Array a.

По этой теме может быть полезным это обсуждение в системе отслеживания ошибок elm. интерес.

person Emmanuel Touzery    schedule 09.09.2016

Поскольку вы хотите обновить все элементы в списке (чтобы убедиться, что все элементы имеют значение False, а те, которые соответствуют идентификатору, имеют значение True), вы можете выполнить List.map по списку, предоставив функцию, задача которой состоит в проверке индекса и выполнении обновление элемента.

Вот пример с несколькими незначительными изменениями в вашем примере кода:

type alias MyTask =
  { description : String
  , focus : Bool
  }

updateElement : List (a, MyTask) -> a -> List (a, MyTask)
updateElement list id =
  let
    toggle (idx, task) =
      if id == idx then
        (idx, { task | focus = True })
      else
        (idx, { task | focus = False })
  in
    List.map toggle list

Я изменил ваши подписи, чтобы они были более общими. Поскольку вы не указали, что такое ID, я предположил, что первый элемент в кортеже должен соответствовать типу второго параметра функции. Я также заменил Task на MyTask, так как в elm уже есть общий тип с именем Task.

Я также упомяну, что существует List.indexedMap function, которая позволит вам немного упростить объявление функции. Если единственная причина, по которой у вас есть ввод и вывод кортежа в приведенном выше примере, заключается в том, что вам нужно найти элемент по его индексу, вероятно, проще использовать List.indexedMap. Вот пример:

updateElement2 : List MyTask -> Int -> List MyTask
updateElement2 list id =
  let
    toggle idx task =
      if id == idx then
        { task | focus = True }
      else
        { task | focus = False }
  in
    List.indexedMap toggle list

Как вы можете видеть, он вырезает из функции некоторые шаблоны кортежей, делая ее немного чище.

person Chad Gilbert    schedule 29.12.2015
comment
Большое спасибо за ваш ответ, я могу использовать это решение где-нибудь еще :-) Но я неправильно выразился по поводу текущей проблемы.. (извините, мой первый пост..) Действительно: введите псевдоним ID = Int, но я хотел бы изменить n-й элемент списка с заданным n. Итак, подпись: updateElement : List (ID, Task) -> Int -> List (ID, Task) Я хочу сделать это, потому что я отсортирую список, но фокус должен оставаться на та же позиция в списке.. Идентификатор в списке имеет другую функциональность. Извините за путаницу, надеюсь, вы все еще можете мне помочь.. - person Thibault; 29.12.2015