5
$\begingroup$

I am not very familiar with coding and I am trying to solve the following:

Input:

{name, John, John Doe, Doe}

Output:

{name, John Doe}

So, it should delete {John, Doe} only if there is a string which contains already both of them.

I would be very grateful for any help! Thank you very much!

$\endgroup$
  • 1
    $\begingroup$ Welcome to the forum! You should watch the TOUR ;-) $\endgroup$ – Vitaliy Kaurov Apr 24 at 21:10
6
$\begingroup$
strings = {"name", "John", "John Doe", "Doe"};

Pick[strings,
 BitAnd @@ (IdentityMatrix[Length[strings]] +
    Boole[Outer[StringFreeQ, strings, strings]]), 1]

{"name", "John Doe"}

Or equivalently:

Pick[strings,
 MapIndexed[StringFreeQ[Delete[strings, #2], #] &, strings],
 ConstantArray[True, Length[strings] - 1]]

The code below matches only whole words:

strings = {"to", "tomorrow", "name", "John", "John Doe", "Doe"}

Pick[strings,
 And @@@ MapIndexed[StringFreeQ[Delete[strings, #2],
     " " | StartOfString ~~ # ~~ EndOfString | " "] &, strings]]

{"to", "tomorrow", "name", "John Doe"}

$\endgroup$
  • $\begingroup$ Great! thank you very much for your help, Coolwater! $\endgroup$ – Coffee_09 Apr 24 at 8:59
  • 1
    $\begingroup$ Is it possible to include a condition that allows the following: Input: {"to", "tomorrow", "name", "John", "John Doe", "Doe"} Output: {"to", "tomorrow", "name", "John Doe"} So, {"to"} should not be deleted. Thank you very much! $\endgroup$ – Coffee_09 Apr 25 at 4:38
  • 1
    $\begingroup$ @Coffee_09 I've updated the answer $\endgroup$ – Coolwater Apr 25 at 10:08
3
$\begingroup$

I'll assume that the list will contain strings, not variables:

L = {"name", "John", "John Doe", "Doe"};

Delete element sequences like {"John", "Doe"} that are together contained in a single string "John Doe":

ClearAll[f];
SetAttributes[f, Orderless];
(f[Sequence @@ #, x___] = f[x]) & /@ Select[StringSplit /@ L, Length[#] > 1 &];
f[x___] = {x};
f @@ L

{"John Doe", "name"}

This method does not keep the original sorting order of the list. If this order needs to be kept, we can replace the last line with

SortBy[f @@ L, Position[L, #][[1, 1]] &]

{"name", "John Doe"}

update

In order to deal with multiple mentions of "John", for example, a slight modification to the Orderless pattern using Repeated ..:

L = {"name", "John", "John", "John Doe", "Doe"};
ClearAll[f];
SetAttributes[f, Orderless];
(f[Sequence @@ Thread[# ..], x___] = f[x]) & /@
  Select[StringSplit /@ L, Length[#] > 1 &];
f[x___] = {x};
SortBy[f @@ L, Position[L, #][[1, 1]] &]

{"name", "John Doe"}

$\endgroup$
  • $\begingroup$ Thank you very much, Roman! Is there a possibility to keep the original sorting order? $\endgroup$ – Coffee_09 Apr 24 at 8:43
  • $\begingroup$ To be honest this is probably not the most efficient solution, but I wrote it down as an exercise in using pattern-matching on Orderless functions. $\endgroup$ – Roman Apr 24 at 8:52
  • $\begingroup$ Thank you very much for your solution, Roman! $\endgroup$ – Coffee_09 Apr 24 at 9:00
2
$\begingroup$
# /. Flatten[Cases[#, 
      x_ /; StringContainsQ[x, " "] :> 
       Thread[StringSplit[x] -> Nothing]]] &[{"name", "John", 
  "John Doe", "Doe"}]

{"name", "John Doe"}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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