Сопоставление шаблонов элементов списка в Mathematica

Следующий шаблон соответствует только первому элементу

{a, b, c, d, e} /. {start : ___, x_, stop : ___} :> {start, 1, stop}

Как мне сделать так, чтобы он соответствовал всем элементам списка?

ОБНОВИТЬ:

Чуть более расширенная версия моей цели состоит в том, чтобы иметь набор из трех правил преобразования для разных элементов списка. Одно правило должно применяться к первому элементу, одно к последнему элементу и еще одно правило к каждому элементу в середине. Вот пример:

{a, b, c, d, e} /. {most : Repeated[_], x_} -> 
   {most, "Last"} /. {x_, rest : Repeated[_]} -> {"First", rest}

Это правила для первого и последнего элемента. Теперь мне нужно правило для всех элементов в середине. Отсюда мой первоначальный вопрос.

Я, вероятно, выбрал неправильный подход, потому что я не могу найти простой способ сделать это. Можно ли это сделать с помощью правил?


person Max    schedule 22.01.2011    source источник


Ответы (2)


Вы можете сделать:

list = Range[10]
list /. {first_, middle__, last_} -> {f[first], g[middle], h[last]}  

Вне

{f[1], g[2, 3, 4, 5, 6, 7, 8, 9], h[10]}  

Или, если вы определяете:

g[x_, y__] = {g[x], g[y]} /. List -> Sequence 

Тогда результат

{f[1], g[2], g[3], g[4], g[5], g[6], g[7], g[8], g[9], h[10]}
person Dr. belisarius    schedule 22.01.2011

Ваш вопрос немного не ясен. Просто догадываюсь, что вы имели в виду - это приведет к самому длинному совпадению:

In[2]:= {a, b, c, d,  e} /. {start : Longest[___], x_, stop : ___} :> {start, 1, stop}

Out[2]= {a, b, c, d, 1}

Хотя это даст все возможные результаты применения правила, а не только первое совпадение:

In[3]:= ReplaceList[{a, b, c, d, e}, {start : ___, x_, stop : ___} :> {start, 1, stop}]

Out[3]= {{1, b, c, d, e}, {a, 1, c, d, e}, {a, b, 1, d, e}, {a, b, c, 1, e}, {a, b, c, d, 1}}

ХТН

Редактировать:

Отвечая на более утонченную версию вопроса, общий ответ будет

{a, b, c, d, e} /. {start_, x__, end_} :> {f[start], g[x], h[end]},

Где, указав функции f,g,h, можно делать любые преобразования отдельно для первого, последнего и среднего элементов. Иногда вы можете использовать правила внутри правил, чтобы сделать его более кратким, например:

In[7]:= {a, b, c, d, e} /. {start_, x__, end_} :> {start /. _ -> "First", 
                   Sequence @@ Replace[{x}, _ -> 1, 1], end /. _ -> "Last"}

Out[7]= {"First", 1, 1, 1, "Last"}

Но главное заключается в том, что после того, как вы деструктурировали список, не имеет значения, что вы используете для преобразования различных частей — снова правила или функции и т. д. — вы не ограничены только использованием правил в этот момент.

person Leonid Shifrin    schedule 22.01.2011
comment
На самом деле я хотел получить в результате {1, 1, 1, 1, 1}. Таким образом, правило будет применяться ко всем элементам списка. - person Max; 22.01.2011
comment
@Max: Тогда это просто неправильный шаблон. Шаблоны, подобные вашему, используются для несколько иных целей, а именно, когда шаблон должен фиксировать некоторые нелокальные взаимозависимости между элементами. Такие шаблоны также часто вызывают значительные накладные расходы, и иногда их также сложно исправить. Поэтому их нужно использовать экономно. В вашем случае, учитывая вашу цель, элементы списка довольно независимы, поэтому я бы сделал это: Replace[{a, b, c, d, e}, _ -> 1, 1] - person Leonid Shifrin; 22.01.2011
comment
@Леонид Шифрин Ну, это не совсем моя цель. Это всего лишь простой пример, демонстрирующий, как я хочу, чтобы шаблон работал. На самом деле я хочу иметь набор из 3 разных правил преобразования. Один для первого элемента, один для последнего и по одному для каждого элемента в середине. У меня не было проблем с шаблонами для первого и последнего элемента. Но я не мог придумать узор для средних элементов. - person Max; 22.01.2011
comment
@ Макс, хорошо, тогда ты не указал четко свою цель в вопросе, по крайней мере, мне трудно связать твой первоначальный запрос с твоей последней формулировкой. Возможно, это ближе к тому, что вам нужно: {a, b, c, d, e} /. {start_, x__, end_} :> {f[start], g[x], h[end]}. Обратите внимание, что вы должны использовать одно подчеркивание для первого и последнего элемента, чтобы выделить их. Затем вы можете указать, что такое f,g,h, в частности, g может преобразовать каждый из элементов в последовательности в 1 и вернуть последовательность единиц. - person Leonid Shifrin; 22.01.2011
comment
@Леонид Шифрин. Можно ли сделать так, чтобы g[] брал один средний элемент за раз, а не все элементы одновременно? - person Max; 22.01.2011
comment
@Max: g - это просто оболочка. Изначально он принимает все средние элементы, но вы можете заставить его обрабатывать их один за другим. См. обновление к моему сообщению - поскольку g является абсолютно произвольным, он будет делать с вашими элементами то, что вы ему прикажете. То, что вы просите сделать напрямую, также возможно, но, скорее всего, будет очень неэффективно для больших списков. - person Leonid Shifrin; 22.01.2011
comment
@Leonid Shifrin Эффективность не является проблемой, потому что списки содержат всего от 100 до 1000 элементов. Я надеялся собрать все правила трансформации в одном месте. - person Max; 22.01.2011
comment
@Max: Не зная более конкретно, чего вы хотите, трудно дать конкретный совет. Если вы хотите это в одном месте, вы можете использовать чистые функции для f,g,h из моего ответа. Но я бы не стал так сильно переживать по этому поводу. Как я уже сказал, после декомпозиции списка вы не обязаны продолжать использовать только (локальные) конструкции на основе правил для дальнейшей обработки частей. На самом деле во многих случаях это не имеет особого смысла. Кроме того, вы можете быть удивлены, но для списков упомянутых вами размеров использование шаблонов с двойными и тройными пробелами может стать проблемой, особенно если вы используете их с ReplaceRepeated. - person Leonid Shifrin; 22.01.2011