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?
Upsample[{0.2, 0.5, 0.7}, 3, 2]
{0., 0.2, 0., 0., 0.5, 0., 0., 0.7, 0.}
(Thanks: corey979)
{0., 0.2, 0., 0.5, 0., 0.7, 0., 0.}
:) thank you.
$\endgroup$
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} *)
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$
Commented
Jan 16, 2018 at 18:22
Span
shifted by one. Not pretty, but if you only need 3, it'll work.
$\endgroup$
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.}
Another option might be
lst = {0.2,0.5,0.7};
Flatten[{0.,#,0.}&/@lst]
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}
Cases[{0.2, 0.5, 0.7}, x_ -> Sequence[0, x, 0], 1]
$\endgroup$
Replace[{0.2, 0.5, 0.7}, x_ :> Sequence[0, x, 0], 1]
.
$\endgroup$
Commented
Jan 17, 2018 at 2:17
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.}
0.
.
$\endgroup$
Commented
Jan 16, 2018 at 16:23
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.
];
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}
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*)
Using Splice
list={0.2,0.5,0.7};
Take[Riffle[list, Splice[{0, 0}], {1, -1, 2}], {2, -2}];
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]
On my machine the timings are more or less the same (with the second one probably a bit faster)
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]}]]
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}
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.}