6

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.

faysou
  • 10,999
  • 3
  • 50
  • 125
  • 4
    Could you explain why not just {{1, 2}, {3, 4}} or {{1, 2}, {3}, {4}} instead of {{1}, {2, 3}, {4}} ? – Artes Jan 03 '13 at 22:43
  • 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. – Mike Honeychurch Jan 03 '13 at 23:04
  • what I mean by my comment is what result do you want from this list: {{1}, {2}, {3}, {4}, {5}} – Mike Honeychurch Jan 03 '13 at 23:34
  • By using part I think the answer of 2013 is the most memory efficient. – faysou Jan 04 '13 at 17:40
  • 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. – Mike Honeychurch Jan 05 '13 at 04:50

7 Answers7

7
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}}
*)
Dr. belisarius
  • 115,881
  • 13
  • 203
  • 453
  • This is a bit terse. The OP may well need and deserve a little explanation to go with it. – m_goldberg Jan 04 '13 at 02:13
  • @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. – Dr. belisarius Jan 04 '13 at 02:32
  • @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 – Dr. belisarius Jan 04 '13 at 02:42
  • I got your point and didn't take any offense. Rather than edit your answer, I decided to offer one of my own, – m_goldberg Jan 04 '13 at 03:46
  • @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},...} – user 3 50 Aug 05 '15 at 22:15
  • @user350 Join @@@ Partition[{{a}, {b}, {c}, {d}, {e}, {f}}, 2] – Dr. belisarius Aug 05 '15 at 22:22
  • @belisarius Works nice! thanks:) What about if one of those lettes represented a whole list and on would want the result to look like: {{{a},{b}},{{c},{d}},{{e},{f}}} ok i've found it myself, sorry. it is Join @ Partition[{{a}, {b}, {c}, {d}, {e}, {f}}, 2] – user 3 50 Aug 05 '15 at 23:00
7

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 :-)

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
  • 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 – Rojo Jan 05 '13 at 04:06
  • @Rojo. You're right but I didn't have that information when I wrote this answer. – m_goldberg Jan 05 '13 at 04:19
5
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]]
Mike Honeychurch
  • 37,541
  • 3
  • 85
  • 158
  • 1
    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. – Mr.Wizard Jan 04 '13 at 21:39
  • 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. – Mike Honeychurch Jan 04 '13 at 21:57
  • 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. – Mike Honeychurch Jan 04 '13 at 22:11
  • 1
    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. – Mr.Wizard Jan 04 '13 at 23:23
  • @Mr.Wizard yes I kind of understood what you were asking but I guess the thing was the question -- for me -- was ambiguous w.r.t intended real usage (though his edit sheds a little more light). The answer as provided gives an output cell with a list in the format he was seeking. – Mike Honeychurch Jan 05 '13 at 04:48
  • @Mr.Wizard Is there actually a way to directly see the result of list[[3]]=Sequence[], i.e., {1,2,Sequence[],...}? Maybe this is a useless question but I'm curious... – sebhofer Jan 05 '13 at 14:11
  • 1
    @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. – Mr.Wizard Jan 05 '13 at 18:24
  • @Mr.Wizard That's a quite complicated construction, it will take me a while to parse it properly. It seems to be very useful though! – sebhofer Jan 06 '13 at 01:34
4

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}}

eldo
  • 67,911
  • 5
  • 60
  • 168
3

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}}
István Zachar
  • 47,032
  • 20
  • 143
  • 291
3

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}}

bmf
  • 15,157
  • 2
  • 26
  • 63
2

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}})

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44