8

I have a list of text and need to replace an element based on the text that appears in the element before it. Example of my list:

list={{"yes","can","fgh"},{"yes","can",""},{"yes","not","fgh"},{"yes","can","srts"},
      {"yes","not","h"}}

I would like to replace all items in column 3 with "This" when column 2's entry is "can".

I have tried to do this using /. and If but without success. I think I need to use a rule but don't know the first thing about how to do this.

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
lara
  • 1,028
  • 7
  • 17

4 Answers4

11

Try this:

Replace[list, {x_, "can", _} :> {x, "can", "This"}, 1]

OR

list /. {x_, "can", _} :> {x, "can", "This"}
{{"yes", "can", "This"}, {"yes", "can", "This"}, {"yes", "not", "fgh"},
 {"yes", "can", "This"}, {"yes", "not", "h"}}

As per your comment, use Alternatives (|):

Replace[list, {x_, y : "can" | "cann", _} :> {x, y, "This"}, 1]
RunnyKine
  • 33,088
  • 3
  • 109
  • 176
  • Can you please walk me through what these symbols mean so I can use them in future? The first option you have given I read like this: – lara Oct 13 '14 at 02:04
  • 1
    @LaraJordan Sure. What I've done here is use rules with pattern matching. With Replace, Mathematica tries to match the first argument using rules provided in the second argument. In this case the first argument is your original list which containes a list of triples. So I matched those triples with the rule {x_, "can", _}. What this rule says is match any triple where the second column is "can", then using :> (RuleDelayed), I then replace the matched triples with {x, "can", "This"}, where I keep the first two columns the same but replace the third column with the desired "This" – RunnyKine Oct 13 '14 at 02:13
  • This is a good resource, if you're not familiar with Mathematica – RunnyKine Oct 13 '14 at 02:18
  • Thanks, that pretty much solves it but I have an addition to the question. What if instead of just replacing all items in column 3 with "This" when column 2's entry is "can", I also want to apply this rule when items in column 2 are any in a list {"can","cann",...}. I have tried using Table but this just gives me x sets of lists, each one with one rule applied. – lara Oct 13 '14 at 02:45
  • @LaraJordan See my update. – RunnyKine Oct 13 '14 at 02:51
  • So instead of writing "can" | "cann" ....how do I refer to the list {"can","cann",...} and not hard code the items? That is why I thought of using Table, something like Replace[list, {x_, y : {list}[[i]],_} :> {x, y, "This"}, 1] – lara Oct 13 '14 at 02:53
  • @LaraJordan What do you mean by hardcode the list? you have to know this list beforehand, so you can save it as a variable e.g. ss = Alternatives["can", "cann", ...], then use ss in the code above. – RunnyKine Oct 13 '14 at 02:59
  • So I can say Replace[list, {x_, y : ss,_} :> {x, y, "This"}, 1] ? I thought I'd have to refer to an element of like Table[Replace[list, {x_, y : ss[[i]], _} :> {x, y, "This"}, 1],{i,1,10}] for example and that would leave me with something I didn't want. Could you elaborate as to how I'd use ss(the list of alternatives) in the example instead of writing out the whole list? – lara Oct 13 '14 at 03:36
  • @LaraJordan Use ss like this: Replace[list, {x_, y : ss, _} :> {x, y, "This"}, 1] – RunnyKine Oct 13 '14 at 04:00
2
list = {{"yes", "can", "fgh"}, {"yes", "can", ""}, {"yes", "not", "fgh"}, 
        {"yes", "can", "srts"}, {"yes", "not", "h"}};

An alternative is to use ReplacePart as follows:

ReplacePart[#, Position[#, {x_, "can", _}] -> {"yes", "can", "This"}] &@list
{{"yes", "can", "This"}, {"yes", "can", "This"}, {"yes", "not", "fgh"},
 {"yes", "can", "This"}, {"yes", "not", "h"}}

Or using ReplaceList with SubsetMap:

pos = ReplaceList[#, {___, s : {x_, "can", _}, ___} :> 
      {Splice @@ Position[#, s], Length@s}] &@list;

SubsetMap[Array["This" &, Length@pos] &, list, pos]

{{"yes", "can", "This"}, {"yes", "can", "This"}, {"yes", "not", "fgh"},
 {"yes", "can", "This"}, {"yes", "not", "h"}}
E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
2
list = 
 {{"yes", "can", "fgh"}, {"yes", "can", ""}, {"yes", "not", "fgh"}, 
  {"yes", "can", "srts"}, {"yes", "not", "h"}};

 p = Position[list, "can"] /. {a_, _} :> {a, 3}

MapAt["This" &, p] @ list

{{"yes", "can", "This"}, {"yes", "can", "This"}, {"yes", "not", "fgh"}, {"yes", "can", "This"}, {"yes", "not", "h"}}

Also

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

and

ReplacePart[p :> "This"] @ list

(* same result *)

eldo
  • 67,911
  • 5
  • 60
  • 168
1
Clear["Global`*"]
list = {{"yes", "can", "fgh"}, {"yes", "can", ""}, {"yes", "not", 
   "fgh"}, {"yes", "cann", "srts"}, {"yes", "not", "h"}}

Using SequenceReplace:

SequenceReplace[list, {{a_, b : "can" | "cann", _}} :> {a, b, "This"}]

Using SequenceCases: (for comparison with SequenceReplace only)

SequenceCases[list, {{a_, b_, c_}} :> 
  If[StringMatchQ[b, "can" | "cann"], {a, b, "This"}, {a, b, c}]]

Result:

{{"yes", "can", "This"}, {"yes", "can", "This"}, {"yes", "not",
"fgh"}, {"yes", "cann", "This"}, {"yes", "not", "h"}}

Syed
  • 52,495
  • 4
  • 30
  • 85