14
$\begingroup$

Given the list

{0.2, 0.5, 0.7}

my desired list is:

{0., 0.2, 0., 0., 0.5, 0., 0., 0.7, 0.}

Can it be done in a smarter way especially for a list with a much larger number (say 1000) of elements?

$\endgroup$
0

14 Answers 14

16
$\begingroup$
Upsample[{0.2, 0.5, 0.7}, 3, 2]

{0., 0.2, 0., 0., 0.5, 0., 0., 0.7, 0.}

(Thanks: corey979)

$\endgroup$
1
  • $\begingroup$ @corey979, right; OPI thought OP wanted {0., 0.2, 0., 0.5, 0., 0.7, 0., 0.}:) thank you. $\endgroup$
    – kglr
    Commented Jan 16, 2018 at 18:46
8
$\begingroup$

This should be fast:

addZeros[arr_] :=
 Module[{res = ConstantArray[0, 3 Length[arr]]},
  res[[2 ;; -2 ;; 3]] = arr;
  res
 ]

If you use floating point numbers instead of integers, use 0. in ConstantArray instead of 0 for improved performance.


Here's a performance-focused version:

iAddZeros[arr_, z_] := 
 Module[{res = ConstantArray[z, 3 Length[arr]]}, 
  res[[2 ;; -2 ;; 3]] = arr;
  res
 ]

addZeros[arr_ /; Developer`PackedArrayQ[arr, Real]] := iAddZeros[arr, 0.]

addZeros[arr_ /; Developer`PackedArrayQ[arr, Complex]] := iAddZeros[arr, 0. + 0. I]

addZeros[arr_] := iAddZeros[arr, 0]

Benchmark:

With[{arr = RandomReal[1, 100000]},
 addZeros[arr]; // RepeatedTiming
 ]
(* {0.00024, Null} *)
$\endgroup$
2
  • $\begingroup$ Can your answer be generalized such that addZeros[arr_,n_] returns {0., 0.2,0.2,0.2, 0., 0., 0.5,0.5,0.5, 0., 0., 0.7,0.7,0.7, 0.} for n=3? I am having a problem to do this using Span. $\endgroup$
    – user36426
    Commented Jan 16, 2018 at 18:22
  • $\begingroup$ You can assign three times, each time with a Span shifted by one. Not pretty, but if you only need 3, it'll work. $\endgroup$
    – Szabolcs
    Commented Jan 16, 2018 at 18:49
8
$\begingroup$
list = {0.2, 0.5, 0.7};
Riffle[ConstantArray[0., 2 Length[list]], list, {2, -2, 3}]
{0., 0.2, 0., 0., 0.5, 0., 0., 0.7, 0.}

If the list-elements should be repeated n times then

n = 3;
With[{z = ConstantArray[0., Length[list]]},
 Flatten[{{z}, ConstantArray[list, n], {z}}, {3, 1, 2}]]
{0., 0.2, 0.2, 0.2, 0., 0., 0.5, 0.5, 0.5, 0., 0., 0.7, 0.7, 0.7, 0.}
$\endgroup$
7
$\begingroup$

Another option might be

lst = {0.2,0.5,0.7};
Flatten[{0.,#,0.}&/@lst]

Mathematica graphics

$\endgroup$
5
$\begingroup$
Replace[{0.2, 0.5, 0.7}, x_ :>  Sequence[0, x, 0], 1]

{0, 0.2, 0, 0, 0.5, 0, 0, 0.7, 0}

Edit

As Alexy Popkov pointed out in a comment (and thanks!), it is safer to use rule-delayed as x is then effectively locally scoped,

 x = 100; Replace[{0.2, 0.5, 2}, x_ :> Sequence[0, x, 0], 1];

{0, 0.2, 0, 0, 0.5, 0, 0, 2, 0}

rather than (original answer):

x = 100; Replace[{0.2, 0.5, 2}, x_ ->  Sequence[0, x, 0], 1]

{0, 100, 0, 0, 100, 0, 0, 100, 0}

$\endgroup$
3
  • $\begingroup$ Or Cases[{0.2, 0.5, 0.7}, x_ -> Sequence[0, x, 0], 1] $\endgroup$
    – user1066
    Commented Jan 17, 2018 at 1:05
  • 1
    $\begingroup$ It is safer to use scoped version: Replace[{0.2, 0.5, 0.7}, x_ :> Sequence[0, x, 0], 1]. $\endgroup$ Commented Jan 17, 2018 at 2:17
  • $\begingroup$ @AlexeyPopkov Thanks! I had naively assumed that x was scoped locally in both constructs. $\endgroup$
    – user1066
    Commented Jan 17, 2018 at 12:49
4
$\begingroup$

Given a list of 1000 elements, say,

SeedRandom[42]; data = RandomReal[1., 1000];

there are many ways to do what you ask for. Here is one using Riffle.

augmented = 
  {0., Sequence @@ Riffle[data, Unevaluated @ Sequence[0., 0.]], 0.};

which produces

Short[augmented, 3]

{0., 0.425905, 0., 0., 0.391023, 0., 0., <2986>>, 0., 0., 0.185166,0., 0., 0.249098, 0.}

$\endgroup$
4
  • 1
    $\begingroup$ The OP wants the first element also to be 0.. $\endgroup$ Commented Jan 16, 2018 at 16:23
  • $\begingroup$ @AlexeyPopkov. Thanks for pointing that out. I have corrected my answer. $\endgroup$
    – m_goldberg
    Commented Jan 16, 2018 at 16:30
  • 2
    $\begingroup$ OP also inserts 2 zeros in-between, not one. $\endgroup$ Commented Jan 16, 2018 at 16:33
  • $\begingroup$ @AlexeyPopkov. Maybe I finally got it right this time? $\endgroup$
    – m_goldberg
    Commented Jan 16, 2018 at 19:36
4
$\begingroup$

Here is a soluton based on SparseArray. It's not as fast as Szabolcs' approach, though, even if one removes Normal.

Normal@SparseArray[
 Transpose[3 Range[{Length[data]}] - 1] -> data, 
 {3 Length[data]},
 0.
];
$\endgroup$
4
$\begingroup$
list = {0.2, 0.5, 0.7};

SequenceCases[list, {x_} :> Sequence @@ {0, x, 0}]

Cases[list, x_ :> Sequence @@ {0, x, 0}]

Sequence @@@   Transpose[{ConstantArray[0, Length@list], list,     ConstantArray[0, Length@list]}]

Sequence @@ ArrayPad[#, {1, 1}] & /@ List /@ list

{0, 0.2, 0, 0, 0.5, 0, 0, 0.7, 0}

$\endgroup$
4
$\begingroup$

Another method using Insert:

PositionsToInsert[list_] := Outer[List, Sequence @@@ MapAt[-#[[2 ;; -2]] &, 
Array[Range[Length@list + 1] &, 2], {2}]]

Using PositionsToInsert with Insert:

Insert[#, 0, PositionsToInsert[#]] &@list

(*{0, 0.2, 0, 0, 0.5, 0, 0, 0.7, 0}*)

An example with another list:

list2 = {a, b, c, d, e};
Insert[#, 0, PositionsToInsert[#]] &@list2 === Cases[list2, x_ :> Sequence @@ {0, x, 0}]

(*True*)
$\endgroup$
4
$\begingroup$

Using Splice

list={0.2,0.5,0.7};

Take[Riffle[list, Splice[{0, 0}], {1, -1, 2}], {2, -2}];
$\endgroup$
3
$\begingroup$

Two more ways to achieve the requested result:

BlockRandom[

 (* generate 1000 random number *)
 rands = RandomReal[{-1,1},1000];

 (* use PadLeft/Right *)
 res1 = Flatten[
   PadLeft[PadRight[{#}, 2], 3] & /@ rands] // RepeatedTiming // Short;

 (* use Riffle *)
 res2 = ReleaseHold[
   Prepend[Append[Riffle[rands, Hold[Sequence[0, 0]]], 0], 0]] // RepeatedTiming // Short;

 {res1, res2}, RandomSeeding->123654789]

(see PadLeft, Riffle)

On my machine the timings are more or less the same (with the second one probably a bit faster)

$\endgroup$
3
$\begingroup$

My slow and naive solution that's also somewhat easy to read:

SeedRandom[42]; data = RandomReal[1., 1000];    
Flatten[Table[Prepend[Append[Take[data,i],0.],0.],{i,Length[data]}]]
$\endgroup$
3
$\begingroup$
list = {0.2, 0.5, 0.7};

Thread[{0, list, 0}] // Flatten

list /. x_?NumberQ :> Splice[{0, x, 0}]

Flatten[Append[0] /@ Prepend[0] /@ List /@ list]

{0, 0.2, 0, 0, 0.5, 0, 0, 0.7, 0}

$\endgroup$
3
$\begingroup$
list = {0.2, 0.5, 0.7};

Using Cases

Cases[list, x_ :> Sequence[0., x, 0.]]

{0., 0.2, 0., 0., 0.5, 0., 0., 0.7, 0.}

Using SequenceReplace (new in 11.3)

SequenceReplace[list, {x_} :> Sequence[0., x, 0.]]

{0., 0.2, 0., 0., 0.5, 0., 0., 0.7, 0.}

$\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.