4
$\begingroup$

I am trying to replace numeric values in the status column below with the text "Dead" using ReplacePart but I'm not getting the desired result. Please help.

YOB status
1910 1982
1977 ALIVE
1951 2012
1977 ALIVE

lis = {{"YOB", "status"}, {1910, 1982}, {1977, "ALIVE"}, {1951, 2012}, {1977, "ALIVE"}}
$\endgroup$
5
  • 1
    $\begingroup$ What have you tried? $\endgroup$
    – Edmund
    Commented Oct 24, 2022 at 23:35
  • 5
    $\begingroup$ lis /. {yrS_, yrF_?NumericQ} :> {yrS, "DEAD"} $\endgroup$
    – Bob Hanlon
    Commented Oct 25, 2022 at 0:23
  • 1
    $\begingroup$ To explain @BobHanlon 's beautiful answer, he creates a RuleDelayed that would replace something with a replacement. Then defines the something as a list with two elements, the first can be anything, but the second must be a number. All those lists are replaced by their same first element and as a second element the word "DEAD." Beautiful! Rule seems to work just as well as RuleDelayed for me, so he might explain if the latter has some advantage that I don't see. $\endgroup$
    – Nicholas G
    Commented Oct 25, 2022 at 0:39
  • 2
    $\begingroup$ @NicholasG - There is no advantage to either Rule or RuleDelayed in this case. I just tend to use RuleDelayed unless there is a reason not to. $\endgroup$
    – Bob Hanlon
    Commented Oct 25, 2022 at 0:46
  • $\begingroup$ Thanks Bob and Nasser. $\endgroup$
    – Joy
    Commented Oct 26, 2022 at 18:51

5 Answers 5

3
$\begingroup$

I am trying to replace the numeric values in the status column below with the text "Dead"

Position returns output designed to be used by ReplacePart. So you can first use Position to find the positions where you want to do the replacement, then use ReplacePart on that.

lis = {{"YOB", "status"}, {1910, 1982}, {1977, "ALIVE"}, {1951, 2012}, {1977, "ALIVE"}}

Mathematica graphics

p = Position[lis[[All, 2]], _?NumericQ]
lis[[All, 2]] = ReplacePart[ lis[[All, 2]], p -> "DEAD"];
MatrixForm[lis]

Mathematica graphics

$\endgroup$
2
$\begingroup$
list = 
 {{"YOB", "status"}, {1910, 1982}, {1977, "ALIVE"}, {1951, 2012}, {1977, "ALIVE"}};

Using SequenceReplace (new in 11.3)

SequenceReplace[list, {{a_, _Integer}} :> {a, "DEAD"}]

{{"YOB", "status"}, {1910, "DEAD"}, {1977, "ALIVE"}, {1951, "DEAD"}, {1977, "ALIVE"}}

Positional solutions

Get replacement positions

p = MapAt[2 &, {All, 2}] @ SequencePosition[list, {{_, _Integer}}]

{{2, 2}, {4, 2}}

ReplaceAt[_ :> "DEAD", p] @ list

ReplacePart[p :> "DEAD"] @ list

MapAt["DEAD" &, p] @ list

All produce

{{"YOB", "status"}, {1910, "DEAD"}, {1977, "ALIVE"}, {1951, "DEAD"}, {1977, "ALIVE"}}

$\endgroup$
1
$\begingroup$

Motivation

Another approach is to convert your data into an Association. It might involve one or two steps beforehand but in my opinion, it makes for safer and more legible code in the long run.

It has numerous advantages over working on a List but the one I find most useful is that I can call a column by its name instead of its index.

For example, your code is more legible with

someBigDataAssociation[[All,"EyeColour"]]

compared to

someBigDataList[[All,42]]

It also makes your code more resilient, what if your data changed and "EyeColour" is no longer in column 42?


Helper Functions

First, we define some helper functions to move between associations and tables with headers.

(* helper functions *)

convertTableWithHeaderToAssociation[table_List] :=
  Module[
   {
    header = First[table],
    body = Rest[table]
    },
   AssociationThread[header, #] & /@ body
   ];

convertAssociationToTableWithHeader[association_List] :=
  Module[
   {
    header = {First[Keys[association]]},
    body = Values[association]
    },
   header~Join~body
   ];

Answer

Convert your data to an Association

birthAndDeathYear = convertTableWithHeaderToAssociation[lis]

{<|"YOB" -> 1910, "status" -> 1982|>, <|"YOB" -> 1977, "status" -> "ALIVE"|>, <|"YOB" -> 1951, "status" -> 2012|>, <|"YOB" -> 1977, "status" -> "ALIVE"|>}

Now we redefine the "status" column applying our NumericQ rule to #status (see Note)

birthAndDeathStatus = <|#, 
    "status" -> If[NumericQ[#status], "DEAD", #status]|> & /@ 
  birthAndDeathYear

{<|"YOB" -> 1910, "status" -> "DEAD"|>, <|"YOB" -> 1977, "status" -> "ALIVE"|>, <|"YOB" -> 1951, "status" -> "DEAD"|>, <|"YOB" -> 1977, "status" -> "ALIVE"|>}

Depending on what you want to do with this data next, you can : inspect it with Dataset ...

Dataset

...or TableForm...

TableForm

or return it to the original format, perhaps to Export it later

convertAssociationToTableWithHeader[birthAndDeathYear]

{{"YOB", "status"}, {1910, 1982}, {1977, "ALIVE"}, {1951, 2012}, {1977, "ALIVE"}}


Note

This makes use of the fact that "Associations keep only the last instance of repeated keys"

for example

<|"a" -> 1, "b" -> 2, "b" -> "bar"|>

<|"a" -> 1, "b" -> "bar"|>

For more information on working with Associations (and Dataset), I found this answer from WReach very helpful.


$\endgroup$
1
$\begingroup$
list = 
 {{"YOB", "status"}, {1910, 1982}, {1977, "ALIVE"}, {1951, 2012}, {1977, "ALIVE"}};

Using Replace at level 1:

Replace[list, {a_, _Integer} :> {a, "DEAD"}, {1}]

{{"YOB", "status"}, {1910, "DEAD"}, {1977, "ALIVE"}, {1951, "DEAD"}, {1977, "ALIVE"}}

$\endgroup$
1
$\begingroup$
list = {{"YOB", "status"}, {1910, 1982}, {1977, "ALIVE"}, {1951, 
    2012}, {1977, "ALIVE"}};

Transpose[{list[[All, 1]], list[[All, 2]] /. _Integer :> "DEAD"}]

list /. {a_, Except["ALIVE" | "status"]} :> {a, "DEAD"}

{{"YOB", "status"}, {1910, "DEAD"}, {1977, "ALIVE"}, {1951, 
  "DEAD"}, {1977, "ALIVE"}}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.