6
$\begingroup$

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?

$\endgroup$
3
  • $\begingroup$ ListNew = If[# > 6000, #/2, #] & /@ List1 or long form: fn = Function[{x}, If[x > 6000, x/2, x]]; ListNew = Map[fn, List1] $\endgroup$ Commented Sep 16, 2020 at 13:15
  • 1
    $\begingroup$ 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. $\endgroup$ Commented Sep 16, 2020 at 13:20
  • $\begingroup$ Big Thanks to all who have helped! You guys are awesome $\endgroup$ Commented Sep 23, 2020 at 7:01

9 Answers 9

8
$\begingroup$
(# + # UnitStep[6000 - #])/2 & @ List1 
{1000, 2000, 3000, 4000, 5000, 6000, 3500, 4000, 4500, 5000} 
$\endgroup$
1
  • $\begingroup$ For long lists this should be fast. $\endgroup$ Commented Sep 16, 2020 at 16:04
6
$\begingroup$

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

ListNew = Table[ If[TrueQ[n > 6000], 0.5 * n, n], {n, List1} ] 
$\endgroup$
1
  • $\begingroup$ Thanks! This helped a lot! $\endgroup$ Commented Sep 23, 2020 at 6:56
5
$\begingroup$
lst//#.DiagonalMatrix[Clip[UnitStep[#-6000],{1,0},{1,1/2}]]& 

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

$\endgroup$
4
$\begingroup$

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!

$\endgroup$
4
  • 4
    $\begingroup$ I recommend using RuleDelayed (:>) instead of Rule (->) for this. $\endgroup$ Commented Sep 16, 2020 at 15:18
  • $\begingroup$ @Sjoerd Smit It would be interesting if you give reasons. It seems that even without RuleDelayed it works. So, what one gains with it? $\endgroup$ Commented Sep 17, 2020 at 7:34
  • 2
    $\begingroup$ 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. $\endgroup$ Commented Sep 17, 2020 at 8:02
  • $\begingroup$ @Sjoerd Smit OK, thank you. $\endgroup$ Commented Sep 17, 2020 at 10:17
4
$\begingroup$

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.

$\endgroup$
3
$\begingroup$

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]] 
$\endgroup$
3
$\begingroup$
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}

$\endgroup$
3
$\begingroup$

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}

$\endgroup$
3
$\begingroup$
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}

$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.