2017-04-10 93 views
0

有沒有一種模式匹配的方式,如[_head |中間| Elixir的_last]?也就是說,我想匹配一個至少包含三件事情(但通常更多)的列表,但只匹配頭部和最後一個元素。Elixir中的模式匹配列表中間

例子:

def match_middle([_head | middle | _last]) do 
     IO.inspect middle 
    end 

    match_middle [1, 2, 3, 4, 5] 
    >>> [2, 3, 4] 
+0

很可能沒有辦法 – JustMichael

+0

你確定你想要模式匹配,而不是隻提取沒有第一個和最後一個元素的列表? – GavinBrelstaff

+0

@GavinBrelstaff我特別想知道模式匹配問題,但如果你有一個簡潔的方法來做到這一點,我想看看它。我目前正在使用想到的第一件事。我沒有看到在評論中格式化代碼的方法....這裏用分號來引導。 [_ |休息] =項目; [_last | rest_backwards] = Enum.reverse rest; middle = Enum.reverse(rest_backwards) – MaxStrange

回答

1

正如你可能會看到,List.pop_at/3本身就是使用遞歸,:lists.reverse,和頭部的訪問來實現。也就是說,沒有辦法直接訪問列表中的最後一個元素。

在另一方面,如果你是關心,有不能超過,比如說,在列表中N元素,直接模式匹配仍然是可以實現的:

defmodule MatchInTheMiddle do 
    @n 10 
    Enum.each([email protected], fn i -> 
    @match_clause Enum.map(0..i, fn j -> {:"p#{j}", [], Elixir} end) 
    def match_middle(unquote(
     [{:_head, [], Elixir}] ++ @match_clause ++ [{:_last, [], Elixir}]) 
    ), do: IO.inspect unquote(@match_clause) 
    end) 
end 

而且,是的,對於短期和長期的名單優雅的回退:

def match_middle([]), do: [] 
def match_middle([_]), do: [] 
def match_middle([_head | tail]) do 
    with [_tail | middle] <- :lists.reverse(tail), do: middle 
end 

MatchInTheMiddle.match_middle([1,2,3,4]) 
#⇒ [2,3] 

這並不像你可能希望它是優雅,但在某些情況下,它可能會有所幫助,因爲這些條款是編譯的到模式匹配和胡ge數據量這是相當有效的,即Enum操作。

+0

這是最接近成爲我可以用於警衛或作爲模式匹配的表達。確實,雖然不是超級優雅。 – MaxStrange

2

Propably我會解決,如果沒有模式匹配,因爲你的情況很特殊 - 你認爲middle是除第一和最後一個元素的一切,但拆分操作者在不同的方式工作 - 它將第一個元素的列表和其他所有內容拆分爲tail

在你的情況,我會爲中間匹配創建私有函數:

defp get_middle_from_list(list) do 
    list 
    |> Stream.drop(1) 
    |> Stream.drop(-1) 
    |> Enum.to_list() 
end 

,並用它

get_middle_from_list [1, 2, 3, 4, 5] 
> [2, 3, 4] 

當然它會返回[]如果列表中包含少於3個元素。

3

Elixir列表是真正的缺點列表,可以回溯到Lisp的早期。

iex(1)> foo = [1 ,2 , 3] 
[1, 2, 3] 
iex(2)> [ head | [ middle | tail ]] = foo 
[1, 2, 3] 
iex(3)> middle 
2 

所以當我們把它寫成[1,2,3]實在是[1, [2,[3,[]]]]

然而,真正不包括你的要求。像這樣的東西也許

def match_middle([_head | [ second | tail]]) when tail != [] do 
    flip_tail = Enum.reverse(tail) 
    [end | rest] = flip_tail 
    [second | Enum.reverse(rest) ] 
end 
+0

老實說,這不是一個「_pattern match_類似'[_head |中間| _last]',「e。 G。它不能用於防範。 – mudasobwa