#wolfram-mathematica
#wolfram-mathematica
Вопрос:
Какой самый чистый способ получения списка в Mathematica
{r1, r2, r3, ..., rn, a, b}
и возврат
{r1, r2, r3, ..., rn, a b}
или в более общем смысле
{r1, r2, r3, ..., rn, f[a, b]}
для какой-то функции f
?
Комментарии:
1. Саймон, я ожидал, что этот вопрос задаст новичок, а не ты. Что именно вам нужно? Позвольте мне перефразировать это: по какой метрике вы будете оценивать ответы? Скорость выполнения? Самый короткий код? Наиболее легко читаемый для новичков Mathematica?
2. @Mr.Wizard: Просто самый чистый код. Я предложил несколько вариантов, но большинство из них меня не устроили. Поэтому я подумал, что, возможно, у кого-то еще есть идея получше. И они сделали — по какой-то причине я полностью отказался от использования
ReplaceAll
!3. @Mr.Wizard: В любом случае — я подумал, что это может быть приятный простой / забавный вопрос после всего того мрачного копания во внутренностях Mma, которое продолжалось!
4. 1, за то, что заставил меня думать, что у меня есть простое решение,
MapAt
, а затем обнаружил, что оно явно не выполняет то, о чем вы просили …
Ответ №1:
lst = {a[1], a[2], a[3], a[4], a[5], a[6], a[7], a, b};
lst /. {a___, b_, c_} -> {a, f[b, c]}
==> {a[1], a[2], a[3], a[4], a[5], a[6], a[7], f[a, b]}
или (некрасиво):
Append[Take[lst, {1, -3}], f @@ lst[[{-2, -1}]]]
Комментарии:
1. Спасибо, Сэр! Первое решение, вероятно, хочет использовать
RuleDelayed
вместоRule
. Также последний элемент можно слегка приукрасить какAppend[lst[[1;;-3]], f@@lst[[-2;;-1]]]
. (конечно, красота в глазах смотрящего и все такое)2. кстати: я полностью забыл об этом
ReplaceAll
при рассмотрении этой проблемы, поэтому все мои решения были похожи на ваше второе (уродливое).3. Интересно, что ваш «уродливый» метод немного быстрее моего, но я думал (в прошлом) Я протестировал аналогичные операции и обнаружил, что опубликованная мной форма работает быстрее. Я думаю, что нет. Возможно, в то время я мог выполнять манипуляции на месте.
4. Вы получаете «галочку», поскольку
/.
она визуально самая четкая, а ваше «уродливое» решение (по словам @Mr.W) самое быстрое!
Ответ №2:
Я бы использовал правила, если производительность не является большой проблемой (списки не упакованы и т.д.):
lst = {a, b, c, d, e}
In[13]:= Replace[lst, {left__, ntl_, l_} :> {left, f[ntl, l]}, {0}]
Out[13]= {a, b, c, f[d, e]}
Комментарии:
1. Леонид, последняя часть вашего кода:
, {0}
что-нибудь делает?2. @Mr.Wizard Да, это так. Это гарантирует, что замена выполняется только в самом выражении, а не в какой-либо из его частей. Я нахожу эту идиому полезной во многих случаях, когда вы хотите сделать свои решения, основанные на правилах, пуленепробиваемыми. Для сравнения,
ReplaceAll
часто приводит к ошибкам, когда правила сопоставляются на другом уровне выражения, чем планировалось.3. Но
Replace
это свойство уже есть, не так ли?Replace[{1, 2, 3}, _Integer -> "x"]
4. @Mr.Wizard По-видимому, вы правы, я только что проверил документы. Я часто использую его со спецификацией другого уровня, например,
{1}
или{2}
, так что, вероятно, у меня вошло в привычку использовать его явно. Здесь, действительно, нет необходимости.
Ответ №3:
Если бы я не переубедил Саймона, я бы ответил первым. Орехи. В любом случае, вот мой ответ с опозданием на вечеринку.
combineLast =
Module[{x = #},
x[[-2]] = #2 @@ x[[-2 ;;]];
Most[x]
] amp;;
Сравнение:
leoCL[lst_, f_] := Replace[lst, {left__, ntl_, l_} :> {left, f[ntl, l]}, {0}]
a = RandomInteger[1*^9, 5000];
Do[combineLast[a, Plus], {5000}] // Timing
Do[leoCL[a, Plus], {5000}] // Timing
{0.078, Null} {1.844, Null}
Комментарии:
1. Вау! Ваш компьютер НАМНОГО быстрее моего! Если вы хотите немного большей скорости, то нарезку списка
[[-2;;]]
можно заменить более явной[[{-2, -1}]]
.2. @Simon, это не должно быть быстрее; это старая машина, использующая процессор начального уровня. Какую версию Mathematica вы используете? Я не удивлюсь, если
[[{-2, -1}]]
это быстрее, но моя любовь к краткости победила.3. Я работаю
8.0.1.0 for Linux x86 (64-bit)
на двухъядерном процессоре AMD Turion 64 X2 в недорогом ноутбуке HP.4. @Simon Мне интересно, почему это происходит медленно на вашем компьютере. Я только что попробовал
[[{-2, -1}]]
, и это слишком близко к вызову, еще один признак того, что поведение отличается. Кажется, я припоминаю, что кто-то в MathGroup жаловался, что Mma 8 работает медленно. Возможно ли вам попробовать эту операцию на Mma 7? Вы проводили какие-либо сравнения скорости, когда получили Mma 8?5. @Simon @Mr. Это в два раза быстрее, чем на моем совершенно новом ноутбуке i7 8-( (mma v8)
Ответ №4:
Предположим, что ‘list’ определен:
Remove[list];
list = {r1, r2, r2, r4, r5, a, b};
Измените значение ‘list’ на {r1, r2, r3, r4, r5, a}, заменив [[-1]] суммой двух последних элементов в ‘list’.
list = ReplacePart[Drop[list, -1], -1 -> Plus @@ list[[-2 ;; -1]]]
Кстати, спасибо, что задали этот вопрос. 🙂
Ответ №5:
Вот мой взгляд на это:
addLastTwo = Function[Append[Drop[#, -2], Total[Take[#, -2]]]];
In[225]:= addLastTwo[{r1, r2, r3, r4, r5}]
Out[225]= {r1, r2, r3, r4 r5}
Это немного быстрее, чем решение мистера Уизарда, хотя и менее общее:
In[226]:= Do[addLastTwo@a, {10000}] // Timing
Out[226]= {0.25, Null}
In[227]:= Do[combineLast[a, Plus], {10000}] // Timing
Out[227]= {0.39, Null}