# List manipulation - adding last element of sublist to each sublist

If I have the following list:

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


How can I add the last element of each sublist to each sublist?

The results should be (empty sublists should be filled with zeros, here I know that I can use the replacement /.{}->{0}):

{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}


lst = {{}, {1, 2}, {}, {2, 4, 3}, {5, 4, 3, 2}, {}} ;
Join[lst, (lst /. {} -> {0})[[All, {-1}]], 2]


{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}

Also

ClearAll[f]; f[{}] = {0}; f[{a___, b_}] := {a, b, b};
f /@ {{}, {1, 2}, {}, {2, 4, 3}, {5, 4, 3, 2}, {}}


{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}

Timings:

ClearAll[f0, f1, f2, f3, f4, f5];
f0[{}] = {0}; f0[{a___, b_}] := {a, b, b};
f1 = f0 /@ # &;
f2 = Join[#, (# /. {} -> {0})[[All, {-1}]], 2] &;
f3 = Replace[#, {{a___, last_} :> {a, last, last}, {} -> {0}}, -1] &; (*MarcoB *)
f4 = Replace[#, {a___, b_} | {} :> {a, b, b + 0}, {1}] &; (* Mr.Wizard *)
f5 = # /. {{} -> {0}, _ :> # ~ Join~{#[[-1]]}} & /@ # &; (* Fraccalo *)
f6 = Append[#, If[# == {}, 0, #[[-1]]]] & /@ # &; (* GIM *)

SeedRandom[1]
testlst = RandomInteger[10, #] & /@ RandomInteger[10, 1000000];
t1 = First[AbsoluteTiming[r1 = f1@testlst;]];
t2 = First[AbsoluteTiming[r2 = f2@testlst;]];
t3 = First[AbsoluteTiming[r3 = f3@testlst;]];
t4 = First[AbsoluteTiming[r4 = f4@testlst;]];
t5 = First[AbsoluteTiming[r5 = f5@testlst;]];
t6 = First[AbsoluteTiming[r6 = f6@testlst;]];
Equal[r1, r2, r3, r4, r5, r6]


True

Grid[Prepend[SortBy[Transpose[{{"f1", "f2", "f3", "f4", "f5", "f6"},
{t1, t2, t3, t4, t5, t6}}], Last], {"function", "timing"}], Dividers -> All]


A single-Rule method using Alternatives:

in = {{}, {1, 2}, {}, {2, 4, 3}, {5, 4, 3, 2}, {}};

Replace[in, {a___, b_} | {} :> {a, b, b + 0}, {1}]

{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}


Some additional examples that may help in understanding this code:

Replace[
{{}, {1, 2}, {}, {2, 4, 3}, {5, 4, 3, 2}, {}},
{{a___, last_} :> {a, last, last}, {} -> {0}},
-1
]

(* Out:  {{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}} *)

• Great ... thank you
– lio
Commented Jun 29, 2018 at 17:49

One line solution, just for fun:

# /. {{} -> {0}, _ :> #~Join~{#[[-1]]}} & /@ list


{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}

You can also use Append and an If statement, and this is fairly quick: if the list is empty, append a 0, else append the last element in the list, and map this function across your input:

Append[#, If[# == {}, 0, #[[-1]]]] & /@ {{}, {1, 2}, {}, {2, 4, 3}, {5, 4, 3, 2}, {}}


For timing, use AbsoluteTiming to get:

AbsoluteTiming[
Append[#, If[# == {}, 0, #[[-1]]]] & /@ {{}, {1, 2}, {}, {2, 4,3}, {5, 4, 3, 2}, {}}]


{0.000024, {{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}}

Using two-argument form of Last:

h = Map[Append[#, Last[#, 0]] &];


Example:

h @ {{}, {1, 2}, {}, {2, 4, 3}, {5, 4, 3, 2}, {}}

{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}

• Thanks, very useful for me in in many other cases too
– eldo
Commented Oct 21, 2023 at 9:29

Using SequenceReplace:

lst = {{}, {1, 2}, {}, {2, 4, 3}, {5, 4, 3, 2}, {}}
SequenceReplace[lst, {{{}} :> {0}, {{a__, b_}} :> {a, b, b}}]


{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}

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


1.

add[{a__, b_}] := {a, b, b}



{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}

2.

ReplaceAt[list, {{} :> {0}, {a__, b_} :> {a, b, b}}, All]


{{0}, {1, 2, 2}, {0}, {2, 4, 3, 3}, {5, 4, 3, 2, 2}, {0}}

ReplaceAt was introduced with V 13.1

Another way is to use Cases and If as follows:

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

Cases[list, x_ :> If[x == {}, Append[x, 0], Append[x, Last@x]]]

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


Or using ReplaceList:

ReplaceList[#, {{a___, b_} :> Splice@{a, b, b}, {} -> 0}] & /@ list

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