6
$\begingroup$

Is there a way to add elements to a list at positions outside the current list's length? Something equivalent to the following MATLAB code snippet:

x = [1,2,3];
x(5) = 5

which returns:

x =

     1     2     3     0     5
$\endgroup$
1
  • 1
    $\begingroup$ Sorry if the following is obvious to you (also, it's a bit off-topic): This is bad practice in MATLAB and in a direct translation also in Mathematica, as in this way new memory needs to be allocated every time you add an element and this takes a lot of time. Better preallocate by x=zeros(1,n). (Of course this doesn't matter much if you do it only once in the whole program.) $\endgroup$
    – sebhofer
    Commented Jul 23, 2014 at 8:51

4 Answers 4

6
$\begingroup$
test = {1, 2, 3}

addEm[list_, position_, ele_] := 
 Module[{tmp = Join[list, ConstantArray[0, position - Length@list]]}, 
  tmp[[position]] = ele; tmp]

addEm[test, 6, 55]

(* {1, 2, 3, 0, 0, 55} *)

You'll probably want to add sanity checks...

$\endgroup$
2
  • 7
    $\begingroup$ It's neater to use PadRight. $\endgroup$
    – C. E.
    Commented Jul 23, 2014 at 1:18
  • $\begingroup$ Thank you both! I thought there was a native way to do it but I was wrong! $\endgroup$
    – Wolfy
    Commented Jul 23, 2014 at 1:33
7
$\begingroup$

why not simply:

x2[n_, a_] := PadRight[x, n, 0] + (SparseArray[n -> a] // Normal)

x2[10,5]

(*{1, 2, 3, 4, 0, 0, 0, 0, 0, 5}*)
$\endgroup$
5
$\begingroup$

More for my own personal edification and possible enlightenment from more experienced users, here are two other possibilities. First, Use a sparse array with a size much larger than expected.

a = Range@3;
b = SparseArray[a, 10^7];

It results in a bit of overhead

ByteCount /@ {a, b}
(* {128, 720} *)

Which decreases with increasing (initial) array size

Table[With[{a = Range@x, b = SparseArray[Range@x, 10^7]}, {x, 
ByteCount[b]/ByteCount[a]}], {x, 5, 1000, 5}] // ListLinePlot

enter image description here

Assign away

b[[5]] = 5
(* 5 *)

Normal will return an array of Length defined in the Sparse Array

Length[Normal[b]]
(* 10000000 *)

Create a "normal" array without padding using ArrayRules

ArrayRules[b]
(* {{1} -> 1, {2} -> 2, {3} -> 3, {5} -> 5, {_} -> 0} *)
Normal@b[[1 ;; First@First@Last@Most@Sort@ArrayRules[b]]]
(* {1, 2, 3, 0, 5} *)

Second, with v10, we can emulate this behavior with Associations. This is food for thought, and I haven't thought much about it yet.

c = Association@ MapIndexed[First@#2 -> #1 &, {1, 2, 3}]
(* <|1 -> 1, 2 -> 2, 3 -> 3|> *)

Add an element with AppendTo

AppendTo[c, 5 -> 5]
(* <|1 -> 1, 2 -> 2, 3 -> 3, 5 -> 5|> *)

Note that single brackets are used in Key/Value associations

c[5]
(* 5 *)

The problem (feature?) here is that missing elements are indicated as such

c[4]
(* Missing["KeyAbsent", 4] *)

Convert to an array when you are done "messing" with the elements

SparseArray[Normal[c]] // Normal
(* {1, 2, 3, 0, 5} *)
$\endgroup$
1
  • $\begingroup$ +1. Turns out you can use Lookup with a default value. e.g.: Lookup[c, {1, 2, 3, 4, 5}, 0] $\endgroup$
    – RunnyKine
    Commented Jul 23, 2014 at 2:14
3
$\begingroup$

Playing with UpValues:

Unprotect@Part;
Part/:Set[Part[list_,part_],value_]:=
    list=MapAt[value&,If[Length@list<part,PadRight[list,part],list],part]
Protect@Part;

Now you can do:

l = {1, 2, 3, 4};
l[[10]] = "x"

and get:

{1, 2, 3, 4, 0, 0, 0, 0, 0, "xx"}

Important: I do not recommend to Unprotect system symbols.

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