# Substitute an element X in a list with 0.5*X

I have a list with 33600 Elements and I have to replace every element bigger than 6000 with its half. I "practiced" with a smaller list and tried the following:

List1 = {1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};
ListNew = {};

Do[
{
Numb = Take[List1, n ;; n],
NumbNew = 0.5 Numb,

ConditionalExpression[Numb > 9000,

ListNew = Append[ListNew, NumbNew]],

ListNew = Append[ListNew, Numb]
}
,
{n, 1, Length[List1]}]


I want ListNew to look like this:

{1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 5000}

But what I get is this:

{5000., 1000, 5000., 2000, 5000., 3000, 5000., 4000, 5000., 5000,
5000., 6000, 5000., 7000, 5000., 8000, 5000., 9000, 5000., 10000}

I tried to use If too, but neither did it work

Is there any way to fix this?

• ListNew = If[# > 6000, #/2, #] & /@ List1 or long form: fn = Function[{x}, If[x > 6000, x/2, x]]; ListNew = Map[fn, List1] Sep 16, 2020 at 13:15
• Also your question is a bit inconsistent. You ask for > 6000 at the top paragraph, and yet in your code you've written > 9000 and your expected answer looks like you've used > 9000 too. As for your coding style, avoid procedural Do loops and Append, and instead prefer functional constructs like Map wherever possible except where the procedural approach is absolutely necessary. Sep 16, 2020 at 13:20
• Big Thanks to all who have helped! You guys are awesome Sep 23, 2020 at 7:01

(# + # UnitStep[6000 - #])/2 & @ List1

{1000, 2000, 3000, 4000, 5000, 6000, 3500, 4000, 4500, 5000}

• For long lists this should be fast.
– kglr
Sep 16, 2020 at 16:04

A method close to the one the OP was going for:

ListNew = Table[
If[TrueQ[n > 6000], 0.5 * n, n],
{n, List1}
]

• Thanks! This helped a lot! Sep 23, 2020 at 6:56
lst//#.DiagonalMatrix[Clip[UnitStep[#-6000],{1,0},{1,1/2}]]&


{1000, 2000, 3000, 4000, 5000, 3000, 3500, 4000, 4500, 5000}

Try this:

lst1 = {1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};

lst1 /. x_ /; x > 6000 -> x/2

(*  {1000, 2000, 3000, 4000, 5000, 6000, 3500, 4000, 4500, 5000}  *)


Have fun!

• I recommend using RuleDelayed (:>) instead of Rule (->) for this. Sep 16, 2020 at 15:18
• @Sjoerd Smit It would be interesting if you give reasons. It seems that even without RuleDelayed it works. So, what one gains with it? Sep 17, 2020 at 7:34
• x is a very commonly used variable and if it has a value, Rule will not do the right thing here because x will evaluate on the r.h.s. of Rule. Try evaluating x = 1 before doing the replacement with Rule to see what I mean. Generally, any replacement rule that uses pattern matching with variables should be done with RuleDelayed unless you have something very specific in mind. Sep 17, 2020 at 8:02
• @Sjoerd Smit OK, thank you. Sep 17, 2020 at 10:17

Another way:

listnew = List1 (Boole[Thread[List1 <= 6000]] + 1/2 Boole[Thread[List1 > 6000]] )

{1000, 2000, 3000, 4000, 5000, 6000, 3500, 4000, 4500, 5000}


The first Boole is 1 when the list numbers are smaller than 6000 and the second Boole is 1/2... this then is multiplied by the values of List1.

The built-in functions Piecewise and Map are good for this kind of thing. Simply, define a piecewise function that implement your condition and map over your list to get a new one. Like so:

With[{max = 9000}, f[x_] := Piecewise[{{x, x ≤ max}, {x/2, x > max}}]]
new = f /@ {1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000}


{1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 5000}

This more concise form will work as well, but is a little less readable:

With[{max = 9000}, f[x_] := Piecewise[{{x, x ≤ max}}, x/2]]

list = {1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};


Some positional solutions

p = Position[list, x_ /; x > 6000]


Using ReplaceAt (new in 13.1)

ReplaceAt[x_ :> x/2, p] @ list


Using SubsetMap (new in 12.0)

SubsetMap[#/2 &, list, Flatten @ p]


Using MapAt

MapAt[#/2 &, p] @ list


All return

{1000, 2000, 3000, 4000, 5000, 6000, 3500, 4000, 4500, 5000}

Using Sow/Reap:

List1 = {1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};

Scan[If[# > 6000, Sow[#/2], Sow[#]] &, List1] // Reap // Last // First


{1000, 2000, 3000, 4000, 5000, 6000, 3500, 4000, 4500, 5000}

list = {1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};


Another way using Fold:

Fold[If[#2 > 6000, Append[#1, #2/2], Append[#1, #2]] &, {}, list]


{1000, 2000, 3000, 4000, 5000, 6000, 3500, 4000, 4500, 5000}

Or using FoldWhile:

f = Append[#1, If[#2 > 6000, #2/2, #2]] &;

FoldWhile[f, {}, list, #1 == {} || Last[#1] <= 6000 & ]


{1000, 2000, 3000, 4000, 5000, 6000, 3500, 4000, 4500, 5000}