6
$\begingroup$

What's the best way to join two consecutive lists in a list of lists ?

For example if I have the list

x = {{1}, {2}, {3}, {4}} 

and I want to get in x

{{1}, {2, 3}, {4}}.

I want to join arbitrary positions.

Edit

I want to do this using the least amount of extra memory. Imagine that instead of having numbers I have big lists.

$\endgroup$
5
  • 4
    $\begingroup$ Could you explain why not just {{1, 2}, {3, 4}} or {{1, 2}, {3}, {4}} instead of {{1}, {2, 3}, {4}} ? $\endgroup$
    – Artes
    Commented Jan 3, 2013 at 22:43
  • $\begingroup$ Maybe give a more detailed example. Is it the 2nd and 3rd elements that should be joined or the 2nd and 3rd last elements that should be joined? ...or maybe the middle 2 elements joined?? To much ambiguity. $\endgroup$ Commented Jan 3, 2013 at 23:04
  • $\begingroup$ what I mean by my comment is what result do you want from this list: {{1}, {2}, {3}, {4}, {5}} $\endgroup$ Commented Jan 3, 2013 at 23:34
  • $\begingroup$ By using part I think the answer of 2013 is the most memory efficient. $\endgroup$
    – faysou
    Commented Jan 4, 2013 at 17:40
  • $\begingroup$ Your edit is important information since I'm sure some of these answers would be quite different if they knew up front that you are working with big lists rather than 4 integers. $\endgroup$ Commented Jan 5, 2013 at 4:50

7 Answers 7

7
$\begingroup$
l = {{a}, {b}, {c}, {d}};
j[l_, from_, to_] := {Sequence @@ l[[1 ;; from - 1]], Join @@ l[[from ;; to]], 
                      Sequence @@ l[[to + 1 ;;]]}

j[l, 2, 4]
(*
->{{a}, {b, c, d}}
*)
$\endgroup$
7
  • $\begingroup$ This is a bit terse. The OP may well need and deserve a little explanation to go with it. $\endgroup$
    – m_goldberg
    Commented Jan 4, 2013 at 2:13
  • $\begingroup$ @m_goldberg Feel free to improve the answer in any way you feel it should be done. The OP isn't asking for a Mma course, so it's up to you to interpret his/her need. $\endgroup$ Commented Jan 4, 2013 at 2:32
  • $\begingroup$ @m_goldberg Please don't take the above comment as derogatory. We deal here with users having from none to very advanced Mma knowledge. Faysal has been active here for a long time, so I guess he's able to untangle this piece of code $\endgroup$ Commented Jan 4, 2013 at 2:42
  • $\begingroup$ I got your point and didn't take any offense. Rather than edit your answer, I decided to offer one of my own, $\endgroup$
    – m_goldberg
    Commented Jan 4, 2013 at 3:46
  • $\begingroup$ @belisarius Since i'm not sure if it is worthy of a question on it's own, how would the code differ if you would wish to combine lists by two in a larger set of lists. For example the input would be: {{a},{b},{c},{d},{e},{f}, ...} and the result would be like: {{a,b},{c,d},{e,f},...} $\endgroup$
    – user 3 50
    Commented Aug 5, 2015 at 22:15
7
$\begingroup$

Belisarius' answer works well if you are willing to work with indexes. If you prefer to work in terms of the list elements rather than their positions, here is a rule-based solution.

innerJoin[data : {{_} ..}, a_, b_] := 
  data /. {x___, y : PatternSequence[{a}, ___, {b}], z___} :> {x, Flatten[{y}], z}

innerJoin[{{1}, {2}, {3}, {4}}, 2, 3]

{{1}, {2, 3}, {4}}

innerJoin[{{a}, {b}, {c}, {d}}, a, c]

{{a, b, c}, {d}}

Edit -- new and improved algorithm featuring the under appreciated PatternSequence :-)

$\endgroup$
2
  • $\begingroup$ Now with the OP's edit, I don't see how specifying the starting and ending elements would be a good idea if he wants to join 2 consecutive big lists. The Flatten would also fail if the elements are lists themselves $\endgroup$
    – Rojo
    Commented Jan 5, 2013 at 4:06
  • $\begingroup$ @Rojo. You're right but I didn't have that information when I wrote this answer. $\endgroup$
    – m_goldberg
    Commented Jan 5, 2013 at 4:19
5
$\begingroup$
list = {{1}, {2}, {3}, {4}}

I asked some questions in my comments but in the absence of clarification about what you want, i.e. will this always be applied to 4 element lists, why not just this:

list[[2]] = Flatten[list[[{2, 3}]]];
list[[3]] = Sequence[];
list

(* {{1}, {2, 3}, {4}} *)

or if you want to make it a function -- probably unnecessary because it is a straightforward two step process:

newList[list_List] := Module[{tmp = list}, tmp[[2]] = Flatten[tmp[[{2, 3}]]];
tmp[[3]] = Sequence[]; tmp]

Edit

Since you've said in your edit 4 hours ago that your actual example is big lists in place of the 4 numbers so you probably won't want to display output

list[[2]] = Flatten[list[[{2, 3}]]];
list[[3]] = Sequence[];
list;

or

list[[2]] = Flatten[list[[{2, 3}]]];
list = Delete[list, 3];

newList2[list_List] := Module[{tmp = list}, tmp[[2]] = Flatten[tmp[[{2, 3}]]];
Delete[tmp, 3]]
$\endgroup$
8
  • 1
    $\begingroup$ You should note that list[[3]] = Sequence[]; does not delete elements; evaluation must take place. Do that and you'll get my vote as I was going to suggest the same method. $\endgroup$
    – Mr.Wizard
    Commented Jan 4, 2013 at 21:39
  • $\begingroup$ If you mean that you have to evaluate list as a final step why is that problem? In all methods you have to undertake evaluation steps. In this one the final step is different to other methods. $\endgroup$ Commented Jan 4, 2013 at 21:57
  • $\begingroup$ Reading his edit if he is actually working with large lists he probably won't want to display. I'll make a revision for that case. $\endgroup$ Commented Jan 4, 2013 at 22:11
  • 1
    $\begingroup$ Mike, my point is that after making a list[[__]] = Sequence[] assignment you haven't deleted those elements (which I think you know). This could be very confusing if you then make further assignments with Part as you won't get what you (might) expect. A simple list = list; would do but so would Drop (more flexible than Delete). Anyway, +1. $\endgroup$
    – Mr.Wizard
    Commented Jan 4, 2013 at 23:23
  • 1
    $\begingroup$ @sebhofer IMHO that's far from a useless question. You can see the value by using my step function, e.g. list = Range@5; list[[3]] = Sequence[]; step[list]. I wrote that function to handle just such cases as this. $\endgroup$
    – Mr.Wizard
    Commented Jan 5, 2013 at 18:24
4
$\begingroup$

Using TakeList (new in 11.2) we can get the desired result by successively taking n elements from list.

list = {{1}, {2}, {3}, {4}};

Join @@@ TakeList[list, {1, 2, All}]

{{1}, {2, 3}, {4}}

Or, using István Zachar's example:

list = {{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}}

Join @@@ TakeList[list, {2, 4, All}]

{{1, 2}, {3, 4, 5, 6}, {7, 8}}

$\endgroup$
3
$\begingroup$

A bit more general version with Drop and ReplacePart:

list = List /@ Range@8
{from, to} = {3, 6}; (* specify first and last positions to be joined *)
ReplacePart[Drop[list, {from + 1, to}], from -> Join @@ Take[list, {from, to}]]
{{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}}

{{1}, {2}, {3, 4, 5, 6}, {7}, {8}}

With ReplaceAll and Repeated:

list /. {x : Repeated[_, {from-1}], y : Repeated[_, {to-from+1}], z___} :> {x, Join@y, z}
{{1}, {2}, {3, 4, 5, 6}, {7}, {8}}
$\endgroup$
3
$\begingroup$

Trying to keep up with @eldo

We can use FoldPairList + TakeDrop which were both introduced in v10.2

Join @@@ FoldPairList[TakeDrop, {{1}, {2}, {3}, {4}}, {1, 2, All}] 

to give

{{1}, {2, 3}, {4}}

or testing with the other list that was used in the answers

Join @@@ 
 FoldPairList[
  TakeDrop, {{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}}, {2, 4, All}]

{{1, 2}, {3, 4, 5, 6}, {7, 8}}

$\endgroup$
2
  • 1
    $\begingroup$ (+1) Nicely done, mate! :-) $\endgroup$ Commented Dec 15, 2023 at 5:06
  • 1
    $\begingroup$ @E.Chan-López thanks a lot! :-) $\endgroup$
    – bmf
    Commented Dec 15, 2023 at 5:07
2
$\begingroup$

Using PartitionRagged:

joinLists[l_, a_, b_] := Join @@@ 
                           Internal`PartitionRagged[#, 
                             {a, b, Length@# - Total@{a, b}}] &@l

joinLists[{{1}, {2}, {3}, {4}}, 1, 2]

(*{{1}, {2, 3}, {4}}*)

joinLists[{{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}}, 2, 4]

(*{{1, 2}, {3, 4, 5, 6}, {7, 8}}*)
$\endgroup$
1
  • 1
    $\begingroup$ (+1) and almost 10 now! $\endgroup$
    – bmf
    Commented Dec 15, 2023 at 5:55

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.