6

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
Wolfy
  • 369
  • 2
  • 7
  • 1
    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.) – sebhofer Jul 23 '14 at 08:51

4 Answers4

7

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}*)
Basheer Algohi
  • 19,917
  • 1
  • 31
  • 78
6
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...

ciao
  • 25,774
  • 2
  • 58
  • 139
5

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} *)
bobthechemist
  • 19,693
  • 4
  • 52
  • 138
3

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.

Murta
  • 26,275
  • 6
  • 76
  • 166