Mathematica: идиоматический способ заменить значения в списке, которые соответствуют условию? - PullRequest
4 голосов
/ 11 февраля 2010

Я хочу усечь абсолютные значения ниже эпсилона до 0, например,

Truncate[{-3, -2, -1, 0, 1, 2, 3}, 1.5] -> {-3, -2, 0, 0, 0, 2, 3}

Думаю, я мог бы написать функцию, используя Scan [] и If [], но есть ли более идиоматический "однострочный" способ сделать это в Mathematica?

Ответы [ 3 ]

6 голосов
/ 11 февраля 2010

Множество опций, которые все работают:

Map[If[Abs[#] < 1.5, 0, #] &, {-3, -2, -1, 0, 1, 2, 3}]

или эквивалент:

If[Abs[#] < 1.5, 0, #] & /@ {-3, -2, -1, 0, 1, 2, 3}

или, если вы предпочитаете:

ReplaceAll[{-3, -2, -1, 0, 1, 2, 3}, (x_ /; Abs[x] < 1.5) -> 0]

, что эквивалентно:

{-3, -2, -1, 0, 1, 2, 3} /. (x_ /; Abs[x] < 1.5) -> 0

или

ReplaceAll[{-3, -2, -1, 0, 1, 2, 3}, (x_?(Abs[#] < 1.5 &)) -> 0]

что эквивалентно:

{-3, -2, -1, 0, 1, 2, 3} /. (x_?(Abs[#] < 1.5 &)) -> 0
5 голосов
/ 11 февраля 2010

Встроенная функция Chop - это почти то, что вы ищете (она работает со списками, как в вашем примере). Одним из потенциальных сюрпризов является то, что он не прерывает (усекает) целые числа, а только числа с плавающей запятой. Итак, чтобы ваш пример работал так, как вы ожидаете, сначала преобразуйте свой список в число с плавающей запятой с помощью функции N:

Chop[N@{-3, -2, -1, 0, 1, 2, 3}, 1.5] -> {-3., -2., 0, 0, 0, 2., 3.}

Как показывает Рамашаланка, для такого рода вещей я рекомендую:

If[Abs[#]<1.5&, 0, #]& /@ {-3, -2, -1, 0, 1, 2, 3}

Т.е. лямбда-функция отображается в списке.

2 голосов
/ 30 марта 2011

Вот метод (f3), который почти на порядок быстрее.

Это взято из кода Фреда Саймонса.


f1 = If[Abs[#] < 1.5, 0, #] & /@ # &;

f2 = # /. (x_ /; Abs[x] < 1.5) -> 0 &;

f3 = # (1 - Unitize@Clip[#, {-1.5, 1.5}, {0, 0}]) &;

lst = RandomInteger[{-100, 100}, 5000];

SameQ @@ (#@lst & /@ {f1, f2, f3})

First@Timing@Do[#@lst, {500}] & /@ {f1, f2, f3}

(* Out=  True                  *)

(* Out=  {0.406, 2.282, 0.047} *)
...