5
$\begingroup$

I have a list containing headers of the form a-*; each followed by a variable number of entries:

oldList = {"a-1", "b", "c", "a-2", "d", "e", "f", "a-3", "w"}

I would like to pair each of the headers with subsequent entries to get the following list:

newList = {{a-1,b}, {a-1,c}, {a-2,d}, {a-2,e}, {a-2,f}, {a-3,w}}

I see that there was a similar but not identical question was posed here four years ago. I started by using StringMatchQ and Position to find the position of the elements that contain "-" and then Complement to find which elements need to have the terms containing "-" affixed to them. But Insert doesn't seem to be very flexible and I'd like to avoid a bunch of For loops.

$\endgroup$
1
  • 4
    $\begingroup$ Don't you think you could modify answers to your previous questions to apply them here? $\endgroup$
    – jjc385
    Commented Dec 4, 2017 at 4:47

6 Answers 6

8
$\begingroup$
Join @@ (Thread[{#, {##2}}] & @@@ Split[oldList, StringFreeQ[#2, "a"] &]) 

{{"a-1", "b"}, {"a-1", "c"}, {"a-2", "d"}, {"a-2", "e"}, {"a-2", "f"}, {"a-3", "w"}}

Also,

Flatten[Thread[{#, {##2}}] & @@@ Split[oldList, StringFreeQ[#2, "a"] &], 1]

{{"a-1", "b"}, {"a-1", "c"}, {"a-2", "d"}, {"a-2", "e"}, {"a-2", "f"}, {"a-3", "w"}}

$\endgroup$
5
  • $\begingroup$ My mistake, I should have made it clear that oldList is a list of strings. Both of your solutions lead to {{"a-1", "b"}, {"a-1", "c"}, {"a-1", "a-2"}, {"a-1", "d"}, {"a-1", "e"}, {"a-1", "f"}, {"a-1", "a-3"}, {"a-1", "h"}, {"a-1", "w"}, {"a-1", "z"}} $\endgroup$
    – Suite401
    Commented Dec 4, 2017 at 4:11
  • $\begingroup$ @Suite401, please see the updated version. $\endgroup$
    – kglr
    Commented Dec 4, 2017 at 5:06
  • $\begingroup$ Yes. Thanks /@you, kglr, swish. $\endgroup$
    – Suite401
    Commented Dec 4, 2017 at 5:23
  • $\begingroup$ And one final generalization question, and i'll let go of this issue; $\endgroup$
    – Suite401
    Commented Dec 4, 2017 at 6:34
  • $\begingroup$ I will post it as a new question, and please tell me what the best way to handle these situations, so as not to annoy people. $\endgroup$
    – Suite401
    Commented Dec 4, 2017 at 6:44
6
$\begingroup$

Try this:

Flatten[
  SequenceCases[oldList,
      {left:_Plus,right:Except[_Plus]..}:>Thread[{left,{right}}]]
, 1]
$\endgroup$
3
$\begingroup$
oldList = {"a-1", "b", "c", "a-2", "d", "e", "f", "a-3", "w"}

Split[oldList, LetterQ@#2 &] // 
  Replace[#, {a_, b__} :> Thread[{a, {b}}], 1] & // Catenate

{{"a-1", "b"}, {"a-1", "c"}, {"a-2", "d"}, {"a-2", "e"}, {"a-2",
"f"}, {"a-3", "w"}}

$\endgroup$
3
$\begingroup$
list = {"a-1", "b", "c", "a-2", "d", "e", "f", "a-3", "w"};

A variant of Syed's answer using Cases and Splice

Cases[
 Split[list, StringLength[#2] == 1 &],
 {a_, b__} :> Splice @ Thread[{a, {b}}]]

{{"a-1", "b"}, {"a-1", "c"}, {"a-2", "d"}, {"a-2", "e"}, {"a-2", "f"}, {"a-3", "w"}}

$\endgroup$
1
$\begingroup$
list = {"a-1", "b", "c", "a-2", "d", "e", "f", "a-3", "w"};

A variant of @Syed and @eldo's answers using SequenceReplace and Splice:

SequenceReplace[Split[list, LetterQ[#2] &], {{a_, b__}} :> Splice@Thread[{a, {b}}]]

{{"a-1", "b"}, {"a-1", "c"}, {"a-2", "d"}, {"a-2", "e"}, {"a-2", "f"}, {"a-3", "w"}}

$\endgroup$
1
$\begingroup$

This is based on @Swish answer, but keeping everything string based:

With[{separatorQ = StringMatchQ["a-" ~~ DigitCharacter]},
  Flatten[
    SequenceCases[
      oldList,
      {
        left : _String?separatorQ,
        right : (Repeated[_String?(separatorQ/*Not)])
      } :> Thread[{left, {right}}]
    ],
    1
  ]
]

(* {{a-1,b},{a-1,c},{a-2,d},{a-2,e},{a-2,f},{a-3,w}} *)
$\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.