1

I'd like to create a dynamic multidimensional array in jQuery/JS. But I can't get it to work:

var abc; // tried abc = [];

for (var i = 0; i < 3; i++) {
  $('#' + i).children().each(function() {
    abc[i][] = $(this).val(); // tried with abc[i].push(), abc[i][n] = ...
  });
}

Expected result:

Array (2)
0 Array (1)
0 ["abc", "abc", "abc", "abc", "abc", "abc"] (6)
1 Array (1)
0 ["abc", "abc", "abc", "abc", "abc", "abc"] (6)

Can someone give me I hint?

ERROR: undefined is not an object or Unexpected token ']'

12
  • 1
    abc is not defined. undefined[i] should be identifiable as an issue. Also abc[i][] is not how you create a new sub array. It would be abc[i] = somearray Commented May 20, 2020 at 16:49
  • 2
    You need to initialize abc as an array, as you tried, and then also every element of this array as an array: abc[i] = [] Commented May 20, 2020 at 16:51
  • @Taplar So abc[i] = [$(this).val()];? Commented May 20, 2020 at 16:52
  • Potentially yes. That is syntatically correct. Though you should use this.value instead of $(this).val() Commented May 20, 2020 at 16:52
  • More like var abc=[]; for(i..) { abc[i]=[]; children.each { abc[i].push(this.value) } } Commented May 20, 2020 at 16:55

1 Answer 1

1

create a dynamic multidimensional array in jQuery/JS

Create the base array, then each of the first dimensions initialise as a new array so the values can be pushed into the second dimension.

var arr = [];
for (var i = 0; i < 3; i++) {
  arr[i] = [];
  $('#div' + i).children().each(function() {
    arr[i].push(this.value);
  });
}

var arr = [];
for (var i = 0; i < 3; i++) {
  arr[i] = [];
  $('#div' + i).children().each(function() {
    arr[i].push(this.value);
  });
}
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='wrapper' id="div0">
      <input type='text' value="abc1-1">
      <input type='text' value="abc1-2">
      <input type='text' value="abc1-3">
      <input type='text' value="abc1-4">
      <input type='text' value="abc1-5">
    </div>
    <div class='wrapper' id="div1">
      <input type='text' value="abc2-1">
      <input type='text' value="abc2-2">
      <input type='text' value="abc2-3">
      <input type='text' value="abc2-4">
      <input type='text' value="abc2-5">
    </div>
    <div class='wrapper' id="div2">
      <input type='text' value="abc3-1">
      <input type='text' value="abc3-2">
      <input type='text' value="abc3-3">
      <input type='text' value="abc3-4">
      <input type='text' value="abc3-5">
    </div>

what's the solution with map

Using jquery:

You can use jquery .map rather than loop through .children.each

var arr = [];
for (var i = 0; i < 3; ++i) {
  arr.push($('#div' + i + ">*").map((i,e)=>e.value).toArray());
}

// start with an empty array
var arr = [];

for (var i = 0; i < 3; ++i) {
  arr.push($('#div' + i + ">*").map((i,e)=>e.value).toArray());
}
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div0">
  <input type='text' value="abc1-1">
  <input type='text' value="abc1-2">
  <input type='text' value="abc1-3">
  <input type='text' value="abc1-4">
  <input type='text' value="abc1-5">
</div>
<div id="div1">
  <input type='text' value="abc2-1">
  <input type='text' value="abc2-2">
  <input type='text' value="abc2-3">
  <input type='text' value="abc2-4">
  <input type='text' value="abc2-5">
</div>
<div id="div2">
  <input type='text' value="abc3-1">
  <input type='text' value="abc3-2">
  <input type='text' value="abc3-3">
  <input type='text' value="abc3-4">
  <input type='text' value="abc3-5">
</div>

removing the brittle hardcoded for loop 0..3, you can add a class to each "wrapper" (or use $("#0,#1,#2") and each on the outer)

var arr = [];

$(".wrapper").each((i, e) =>
  arr.push($(e).find(">*").map((ii, ee) => ee.value).toArray())
);

var arr = [];

$(".wrapper").each((i, e) =>
  arr.push($(e).find(">*").map((ii, ee) => ee.value).toArray())
);
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='wrapper' id="div0">
  <input type='text' value="abc1-1">
  <input type='text' value="abc1-2">
  <input type='text' value="abc1-3">
  <input type='text' value="abc1-4">
  <input type='text' value="abc1-5">
</div>
<div class='wrapper' id="div1">
  <input type='text' value="abc2-1">
  <input type='text' value="abc2-2">
  <input type='text' value="abc2-3">
  <input type='text' value="abc2-4">
  <input type='text' value="abc2-5">
</div>
<div class='wrapper' id="div2">
  <input type='text' value="abc3-1">
  <input type='text' value="abc3-2">
  <input type='text' value="abc3-3">
  <input type='text' value="abc3-4">
  <input type='text' value="abc3-5">
</div>

Extending this, it looks like you could use a nested map:

var arr = $(".wrapper").map((i, e) => $(e).find(">*").map((ii, ee) => ee.value).toArray()).toArray();

but, as you'll see from the snippet, this flattens the final array.

var arr = $(".wrapper").map((i, e) => $(e).find(">*").map((ii, ee) => ee.value).toArray()).toArray();
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='wrapper' id="div0">
  <input type='text' value="abc1-1">
  <input type='text' value="abc1-2">
  <input type='text' value="abc1-3">
  <input type='text' value="abc1-4">
  <input type='text' value="abc1-5">
</div>
<div class='wrapper' id="div1">
  <input type='text' value="abc2-1">
  <input type='text' value="abc2-2">
  <input type='text' value="abc2-3">
  <input type='text' value="abc2-4">
  <input type='text' value="abc2-5">
</div>
<div class='wrapper' id="div2">
  <input type='text' value="abc3-1">
  <input type='text' value="abc3-2">
  <input type='text' value="abc3-3">
  <input type='text' value="abc3-4">
  <input type='text' value="abc3-5">
</div>

Using vanilla javascript

These days there's also an Array.prototype.map function ("these days" - it's been around a while...but not forever) which you can use. Sticking with vanilla js to get the DOM elements as well (see below to use jquery and convert to an array) along with some ES6 fancyness to convert from the HTMLCollection to an array gives the one liner:

var arr = [...document.getElementsByClassName("wrapper")].map((e)=>[...e.children].map((ee)=>ee.value))
console.log(arr);

This bit [...document.getElementsByClassName("wrapper")] converts the HTMLCollection to an array so we can use js .map

var arr = [...document.getElementsByClassName("wrapper")].map((e)=>[...e.children].map((ee)=>ee.value))
console.log(arr);
<div class='wrapper' id="div0">
  <input type='text' value="abc1-1">
  <input type='text' value="abc1-2">
  <input type='text' value="abc1-3">
  <input type='text' value="abc1-4">
  <input type='text' value="abc1-5">
</div>
<div class='wrapper' id="div1">
  <input type='text' value="abc2-1">
  <input type='text' value="abc2-2">
  <input type='text' value="abc2-3">
  <input type='text' value="abc2-4">
  <input type='text' value="abc2-5">
</div>
<div class='wrapper' id="div2">
  <input type='text' value="abc3-1">
  <input type='text' value="abc3-2">
  <input type='text' value="abc3-3">
  <input type='text' value="abc3-4">
  <input type='text' value="abc3-5">
</div>

Now this uses nested .map (js .map not jquery .map) and does return the expected multi-dimensional array.

Using jquery selectors and javascript map

Finally, combining the succinctness of jquery selectors (or maybe you already have them as jquery objects so don't want to reselect them, any reason is fine) with js .map to get the nested map in (slightly) shorter code than the vanilla version:

var arr = $(".wrapper").toArray().map(e=>$(">*",e).toArray().map(ee=>ee.value));
console.log(arr);

here: $(selector).toArray() returns an array of DOM elements, so we can use js .map.

var arr = $(".wrapper").toArray().map(e=>$(">*",e).toArray().map(ee=>ee.value));
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='wrapper' id="div0">
  <input type='text' value="abc1-1">
  <input type='text' value="abc1-2">
  <input type='text' value="abc1-3">
  <input type='text' value="abc1-4">
  <input type='text' value="abc1-5">
</div>
<div class='wrapper' id="div1">
  <input type='text' value="abc2-1">
  <input type='text' value="abc2-2">
  <input type='text' value="abc2-3">
  <input type='text' value="abc2-4">
  <input type='text' value="abc2-5">
</div>
<div class='wrapper' id="div2">
  <input type='text' value="abc3-1">
  <input type='text' value="abc3-2">
  <input type='text' value="abc3-3">
  <input type='text' value="abc3-4">
  <input type='text' value="abc3-5">
</div>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.