список понимания плюс сопоставление с образцом - PullRequest
0 голосов
/ 20 мая 2018

Проблема, которую я пытаюсь решить, заключается в следующем: «найти все элементы списка L, за которым следует элемент со значением X».

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

[some_transformation(X) || X <- [...], some_conditional(X)].

. Есть фильтр X, который исходит из генератора X, и преобразование, применяемое к тем, которые проходят.

У меня очень слабая надежда, потому что сила Erlang для сопоставления с образцом допускает такие вещи:

[H1|[H2|T]] = [1,2,3,4].

, которая связывает H1 и H2.Есть ли какой-то шаблон, который я могу использовать в понимании списка для достижения желаемого результата?

Когда я наивно пытаюсь это сделать, он явно не работает:

78> [X||[H1|[H2|_]]=X <- [1,2,3,4]].
[]

Возможно, мне следует остановитьсябыть ленивым и хотите, чтобы магия понимания списка и сопоставления с образцом сделала всю работу за меня?= Р

1 Ответ

0 голосов
/ 20 мая 2018

Вы можете сжать список с последним элементом, отброшенным хвостом списка, а затем использовать понимание списка:

1> List = [1, 2, 3, 2, 1, 2, 2, 1, 1, 3, 1].
[1,2,3,2,1,2,2,1,1,3,1]
2> X = 1.
1
3> Zipped = lists:zip(lists:droplast(List), tl(List)).
[{1,2},
 {2,3},
 {3,2},
 {2,1},
 {1,2},
 {2,2},
 {2,1},
 {1,1},
 {1,3},
 {3,1}]
4> [A || {A, B} <- Zipped, B == X].
[2,2,1,3]

Это неэффективно - создается копия списка (для droplast) и новый заархивированный список.Вы можете использовать рекурсию вот так, чтобы сделать это эффективным:

-module(a).
-export([before/2]).

before(List, X) ->
  before(List, X, []).

before([A, X | Tail], X, Acc) ->
  before([X | Tail], X, [A | Acc]);
before([_ | Tail], X, Acc) ->
  before(Tail, X, Acc);
before([], _, Acc) ->
  lists:reverse(Acc).
1> c(a).
{ok,a}
2> a:before([1, 2, 3, 2, 1, 2, 2, 1, 1, 3, 1], 1).
[2,2,1,3]
...