2
$\begingroup$

Say I have a "seed" SparseArray e.g. m=SparseArray[{1->1}]. How do I add a rule at a position that has not yet been defined e.g. 5->5to get a list of rules {1}->1, (5)->5? I want to build up the sparse array an element at a time. I don't want to have to normalise it as that would appear to defeat the purpose of sparse arrays

It seems like this should be simple.

$\endgroup$
  • 2
    $\begingroup$ Possible duplicate of Efficient by-element updates to SparseArrays $\endgroup$ – Jason B. Jun 15 '18 at 17:57
  • $\begingroup$ Building SparseArrays entry-by-entry cannot be efficient. $\endgroup$ – Henrik Schumacher Jun 15 '18 at 18:13
  • $\begingroup$ Are you reading the array while building it, or only writing to it? If only writing, you don't need to create a SparseArray. The rules are sufficient. If you need a little bit of reading, consider Association, AssociateTo for updating, and Lookup (with a default of 0) for reading. $\endgroup$ – Szabolcs Jun 15 '18 at 18:26
  • $\begingroup$ In the end I used an Association. I was misunderstanding SparseArray semantics. $\endgroup$ – David G Jun 19 '18 at 21:01
3
$\begingroup$

You need to tell the SparseArray how large it will be when you initialize it, then you can just use Part and Set to update it:

m = SparseArray[{1 -> 1}, {10}];
m[[3]] = 3
(* 3 *)

Head@m
(* SparseArray *)

Normal@m
(* {1, 0, 3, 0, 0, 0, 0, 0, 0, 0} *)

From the comments, I would suggest that an Association is a better data structure for this purpose. You can build it up efficiently, and quickly dump it to a SparseArray at the end,

data = <|1 -> 2|>;

(* do something *)
data[4] = 22;
(* do something else *)
data[233] = 55;
(* now that you are done, make a SparseArray *)
SparseArray[ Normal @ data]
(* SparseArray[Automatic, {233}, 0, {
 1, {{0, 3}, {{1}, {4}, {233}}}, {2, 22, 55}}] *)

It will work for a higher dimension array,

data = <|{1, 1} -> 2|>;
data[{45, 33}] = 22;
data[{1000, 233}] = 55;
SparseArray[ Normal @ data]

enter image description here

You can access the stored values, and provide a default value just like for an array

Lookup[data, Key[{1000, 233}], 0]
(* 55 *)

Lookup[data, Key[{1000, 234}], 0]
(* 0 *)
$\endgroup$
  • $\begingroup$ But I don't know how big it will be. I suppose if its internal representation is the least bit efficient I could initialise it to, say, a million elements without incurring too much of a penalty, but that seems ugly. $\endgroup$ – David G Jun 15 '18 at 17:58
  • 3
    $\begingroup$ I wonder then if SparseArray is the right tool to use for this, see the edit $\endgroup$ – Jason B. Jun 15 '18 at 18:08
  • $\begingroup$ I think that you may well be correct. Thanks. $\endgroup$ – David G Jun 15 '18 at 20:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.