Поиск…


замечания

List ( связанный список ) светит в последовательном доступе :

  • доступ к первому элементу
  • добавление к началу списка
  • удаление из передней части списка

С другой стороны, он не идеален для случайного доступа (т. Е. Получения n-го элемента) и прохождения в обратном порядке , и вам может быть повезло (и производительность) с структурой данных Array .

Создание списка по диапазону

0.18.0

До 0.18.0 вы можете создавать такие диапазоны:

> range = [1..5]
[1,2,3,4,5] : List number
>
> negative = [-5..3]
[-5,-4,-3,-2,-1,0,1,2,3] : List number
0.18.0

В 0.18.0 Синтаксис [1..5] удален .

> range = List.range 1 5
[1,2,3,4,5] : List number
>
> negative = List.range -5 3
[-5,-4,-3,-2,-1,0,1,2,3] : List number

Диапазоны , созданные этот синтаксис всегда включают и шаг всегда 1.

Создание списка

> listOfNumbers = [1,4,99]
[1,4,99] : List number
>
> listOfStrings = ["Hello","World"]
["Hello","World"] : List String
>
> emptyList = []   -- can be anything, we don't know yet
[] : List a
>

Под капотом List ( связанный список ) строится функцией :: (так называемые «cons»), которая принимает два аргумента: элемент, известный как глава, и (возможно, пустой) список, к которому добавляется голова.

> withoutSyntaxSugar = 1 :: []
[1] : List number
>
> longerOne = 1 :: 2 :: 3 :: []
[1,2,3] : List number
>
> nonemptyTail = 1 :: [2]
[1,2] : List number
>

List может принимать только значения одного типа, поэтому нечто вроде [1,"abc"] невозможно. Если вам это нужно, используйте кортежи.

> notAllowed = [1,"abc"]
==================================== ERRORS ====================================

-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm

The 1st and 2nd elements are different types of values.

8|              [1,"abc"]
               ^^^^^
The 1st element has this type:

    number

But the 2nd is:

    String

Hint: All elements should be the same type of value so that we can iterate
through the list without running into unexpected values.


> 

Получение элементов

> ourList = [1,2,3,4,5]
[1,2,3,4,5] : List number
>
> firstElement = List.head ourList
Just 1 : Maybe Int
>
> allButFirst = List.tail ourList
Just [2,3,4,5] : Maybe (List Int)

Эта упаковка в тип Maybe происходит из-за следующего сценария:

Что должно List.head возвращать для пустого списка? (Помните, что Elm не имеет исключений или нулей.)

> headOfEmpty = List.head []
Nothing : Maybe Int
>
> tailOfEmpty = List.tail []
Nothing : Maybe (List Int)
>
> tailOfAlmostEmpty = List.tail [1] -- warning ... List is a *linked list* :)
Just [] : Maybe (List Int)

Преобразование каждого элемента списка

List.map : (a -> b) -> List a -> List b - это функция более высокого порядка, которая применяет однопараметрическую функцию к каждому элементу списка, возвращая новый список с измененными значениями.

import String

ourList : List String
ourList = 
    ["wubba", "lubba", "dub", "dub"]

lengths : List Int
lengths = 
    List.map String.length ourList
-- [5,5,3,3]

slices : List String
slices =
    List.map (String.slice 1 3) ourList
-- ["ub", "ub", "ub", "ub"]

Если вам нужно знать индекс элементов, вы можете использовать List.indexedMap : (Int -> a -> b) -> List a -> List b :

newList : List String
newList =
    List.indexedMap (\index element -> String.concat [toString index, ": ", element]) ourList
-- ["0: wubba","1: lubba","2: dub","3: dub"] 

Фильтрация списка

List.filter : (a -> Bool) -> List a -> List a - это функция более высокого порядка, которая принимает однопараметрическую функцию от любого значения до логического и применяет эту функцию к каждому элементу данного списка, сохраняя только те элементы, для которых функция возвращает True . Функция, которую List.filter принимает в качестве своего первого параметра, часто упоминается как предикат .

import String

catStory : List String
catStory = 
    ["a", "crazy", "cat", "walked", "into", "a", "bar"]

-- Any word with more than 3 characters is so long!
isLongWord : String -> Bool
isLongWord string =
    String.length string > 3

longWordsFromCatStory : List String
longWordsFromCatStory = 
    List.filter isLongWord catStory

Оцените это в elm-repl :

> longWordsFromCatStory
["crazy", "walked", "into"] : List String
>
> List.filter (String.startsWith "w") longWordsFromCatStory
["walked"] : List String

Соответствие шаблону в списке

Мы можем сопоставлять списки, как и любой другой тип данных, хотя они несколько уникальны, поскольку конструктор для создания списков - это функция infix :: . (См. Пример Создание списка для более подробного описания того, как это работает.)

matchMyList : List SomeType -> SomeOtherType
matchMyList myList = 
    case myList of
        [] -> 
            emptyCase

        (theHead :: theRest) ->
            doSomethingWith theHead theRest

Мы можем сопоставить столько элементов в списке, сколько хотим:

hasAtLeast2Elems : List a -> Bool
hasAtLeast2Elems myList =
    case myList of
        (e1 :: e2 :: rest) -> 
            True
    
        _ -> 
            False

hasAtLeast3Elems : List a -> Bool
hasAtLeast3Elems myList =
    case myList of
        (e1 :: e2 :: e3 :: rest) -> 
            True
    
        _ -> 
            False

Получение n-го элемента из списка

List не поддерживает «произвольный доступ», что означает, что требуется больше работы, чтобы получить, скажем, пятый элемент из списка, чем первый элемент, и, как следствие, функции List.get nth list . Нужно пройти весь путь с самого начала ( 1 -> 2 -> 3 -> 4 -> 5 ).

Если вам нужен произвольный доступ, вы можете получить лучшие результаты (и производительность) со структурами данных с произвольным доступом, такими как Array , где взятие первого элемента требует такой же работы, как принятие, скажем, 1000-го. (сложность O (1)).

Тем не менее, возможно (но обескураженно) получить n-й элемент:

get : Int -> List a -> Maybe a
get nth list =
    list
        |> List.drop (nth - 1)
        |> List.head

fifth : Maybe Int
fifth = get 5 [1..10]
--    = Just 5

nonexistent : Maybe Int
nonexistent = get 5 [1..3]
--          = Nothing

Опять же, это занимает значительно больше работы, чем больше nth аргумент.

Уменьшение списка до одного значения

В Elm функции сокращения называются «сгибами», и есть два стандартных метода для «складывания» значений: слева, foldl и справа, foldr .

> List.foldl (+) 0 [1,2,3]
6 : number

Аргументами foldl и foldr являются:

  • функция уменьшения : newValue -> accumulator -> accumulator
  • начальное значение аккумулятора
  • список для сокращения

Еще один пример с пользовательской функцией:

type alias Counts =
    { odd : Int
    , even : Int
    }

addCount : Int -> Counts -> Counts
addCount num counts =
    let
        (incOdd, incEven) =
            if num `rem` 2 == 0
                then (0,1)
                else (1,0)
    in
        { counts
            | odd = counts.odd + incOdd
            , even = counts.even + incEven
        }

> List.foldl
      addCount
      { odd = 0, even = 0 }
      [1,2,3,4,5]
{ odd = 3, even = 2 } : Counts

В первом примере выше программа выглядит следующим образом:

List.foldl (+) 0 [1,2,3]
3 + (2 + (1 + 0))
3 + (2 + 1)
3 + 3
6
List.foldr (+) 0 [1,2,3]
1 + (2 + (3 + 0))
1 + (2 + 3)
1 + 5
6

В случае коммутативной функции, такой как (+) на самом деле нет разницы.

Но посмотрите, что происходит с (::) :

List.foldl (::) [] [1,2,3]
3 :: (2 :: (1 :: []))
3 :: (2 :: [1])
3 :: [2,1]
[3,2,1]
List.foldr (::) [] [1,2,3]
1 :: (2 :: (3 :: []))
1 :: (2 :: [3])
1 :: [2,3]
[1,2,3]

Создание списка путем повторения значения

> List.repeat 3 "abc"
["abc","abc","abc"] : List String

Вы можете дать List.repeat любое значение:

> List.repeat 2 {a = 1, b = (2,True)}
[{a = 1, b = (2,True)}, {a = 1, b = (2,True)}]
  : List {a : Int, b : (Int, Bool)}

Сортировка списка

По умолчанию List.sort сортируется в порядке возрастания.

> List.sort [3,1,5]
[1,3,5] : List number

List.sort требует, чтобы элементы списка были comparable . Это означает: String , Char , number ( Int и Float ), List comparable или кортежей comparable .

> List.sort [(5,"ddd"),(4,"zzz"),(5,"aaa")]
[(4,"zzz"),(5,"aaa"),(5,"ddd")] : List ( number, String )

> List.sort [[3,4],[2,3],[4,5],[1,2]]
[[1,2],[2,3],[3,4],[4,5]] : List (List number)

Вы не можете сортировать списки Bool или объектов с помощью List.sort . Для этого см. Раздел Сортировка списка с пользовательским компаратором.

> List.sort [True, False]
-- error, can't compare Bools

Сортировка списка с помощью пользовательского компаратора

List.sortWith позволяет сортировать списки с данными любой формы - вы предоставляете ее с помощью функции сравнения.

compareBools : Bool -> Bool -> Order
compareBools a b =
    case (a,b) of
        (False, True) ->
            LT

        (True, False) ->
            GT

        _ ->
            EQ
        
> List.sortWith compareBools [False, True, False, True]
[False, False, True, True] : List Bool

Перемещение списка

Примечание: это не очень эффективно из-за характера List (см. Примечания ниже). Лучше построить список «правильным» способом с самого начала, чем построить его, а затем отменить его.

> List.reverse [1,3,5,7,9]
[9,7,5,3,1] : List number

Сортировка списка в порядке убывания

По умолчанию List.sort сортирует в порядке возрастания, с функцией compare .

Существует два способа сортировки по убыванию: один эффективный и один неэффективный.

  1. Эффективный способ : List.sortWith и нисходящая функция сравнения.
descending a b =
    case compare a b of
      LT -> GT
      EQ -> EQ
      GT -> LT

> List.sortWith descending [1,5,9,7,3]
[9,7,5,3,1] : List number
  1. Неэффективный способ (обескуражен!) : List.sort а затем List.reverse .
> List.reverse (List.sort [1,5,9,7,3])
[9,7,5,3,1] : List number

Сортировка списка по производному значению

List.sortBy позволяет использовать функцию для элементов и использовать ее результат для сравнения.

> List.sortBy String.length ["longest","short","medium"]
["short","medium","longest"] : List String
-- because the lengths are: [7,5,6]

Он также прекрасно работает с записывающими устройствами:

people =
    [ { name = "John", age = 43 }
    , { name = "Alice", age = 30 }
    , { name = "Rupert", age = 12 }
    ]

> List.sortBy .age people
[ { name = "Rupert", age = 12 }
, { name = "Alice", age = 30 }
, { name = "John", age = 43 }
] : List {name: String, age: number}

> List.sortBy .name people
[ { name = "Alice", age = 30 }
, { name = "John", age = 43 }
, { name = "Rupert", age = 12 }
] : List {name: String, age: number}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow