D3.js v5 concat dynamic arrays

For this particular task, I’m unable to parse data. So I need to hard-code some data with desired format:

var data = ["1Equity","2Equity","3Equity","4Balanced","5Balanced","6MMF","7MMF","8MMF","9MMF","10MMF"];

It is essentially an array with numerous occurrences of several different strings; the actual array will be much longer and so I am searching for a labor-saving device.

I have tried:

d3.range(3).map(function(v) { return v+"equity"}).push(d3.range(2).map(function(v) { return v+"balanced"})).push(d3.range(5).map(function(v) { return v+"mmf"}))

However, this returned:

Uncaught (in promise) d3.range(…).map(…).push(…).push is not a
function

Question

How can I concat arrays with items mapped to several different strings (occurrence of string based on my discression/user configurable) in a single line?

6 thoughts on “D3.js v5 concat dynamic arrays”

  1. Array.prototype.push returns the new length of the array. Therefore you cannot chain it like this (you’re calling push on a number, not an array).

    What you want can be easy to customise with reduce:

    const keys = [
      ["Equity", 3],
      ["Balanced", 2],
      ["MMF", 5]
    ];
    
    const data = keys.reduce((a, c) => a.concat(d3.range(c[1]).map((_, j) => (a.length + (j + 1)) + c[0])), []);
    
    console.log(data)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

    However, if you want to keep that chain of yours, use concat instead of push (as in the very title of your question), but then you’ll have a problem with the indices:

    const data = d3.range(3).map(function(v) { return v+"equity"}).concat(d3.range(2).map(function(v) { return v+"balanced"})).concat(d3.range(5).map(function(v) { return v+"mmf"}));
    
    console.log(data)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    Reply
  2. The error you witnessed is caused by .push() returning the new length of the array, not the array instance, which hinders method chaining.

    In my opinion, your task can easily be done using Vanilla JS without the need to employ D3 at all:

    const structure = [["Equity", 3], ["Balanced", 2], ["MMF", 5]];
    
    let i = 1;
    const data = [].concat(                       // 4. Concatenate all sub-arrays
      structure.map(                              // 1. Iterate structure
        ([k, n]) => new Array(n).fill(undefined)  // 2. Create sub-array of length n for key k
          .map(_ => `${i++}${k}`)                 // 3. Map each item to desired string value
      )
    ).flat();                                     // 5. Flatten to 1-dimensional array
    
    console.log(data);
    Reply

Leave a Comment