12

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}}
kglr
  • 394,356
  • 18
  • 477
  • 896
lio
  • 2,396
  • 13
  • 26

9 Answers9

12
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]

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896
8
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}} *)
MarcoB
  • 67,153
  • 18
  • 91
  • 189
8

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:

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
6

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

Fraccalo
  • 6,057
  • 13
  • 28
6

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

GIM
  • 146
  • 4
5

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}}
kglr
  • 394,356
  • 18
  • 477
  • 896
3

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

Syed
  • 52,495
  • 4
  • 30
  • 85
3
list = {{}, {1, 2}, {}, {2, 4, 3}, {5, 4, 3, 2}, {}};

1.

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

add /@ list

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

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

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

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