How to place two arrays inside a single loop of repetition to populate an object?

Asked

Viewed 170 times

1

Based in that and in that reply, I am creating an instant search box that returns results based on the items of two arrays with elements p and a of certain classes present on the page.

The idea is that the first array (p) be the property name; and the array a be the property url. The code works extremely well, however I do not know how to use the values of my array a to populate the property url of my object people, since the property name works smoothly.

In short, how can I add array items a inside the repeat loop and set its values in the property url?

var p = Array.prototype.slice.call(document.querySelectorAll("[class='h6']")).map(function(x){return x.innerHTML});
var a = Array.prototype.slice.call(document.querySelectorAll("[class='link']")).map(function(y){return y.href});

var people = [];
for (var key in p) {
    if (p.hasOwnProperty(key)) {
        people.push({
            name: p[key],
            url: "A ideia é que apareça a URL presente no parágrafo de nome 'Teste N'"
          })
        console.log(people[key])
    }
}
<a class="link" href="url1.html"><p class="h6">Teste 1</p></a>
<a class="link" href="url2.html"><p class="h6">Teste 2</p></a>
<a class="link" href="url3.html"><p class="h6">Teste 3</p></a>
<a class="link" href="url4.html"><p class="h6">Teste 4</p></a>
<a class="link" href="url5.html"><p class="h6">Teste 5</p></a>

  • 1

    Important you [Dit] your question and explain objectively and punctually the difficulty found, accompanied by a [mcve] of the problem and attempt to solve. To better enjoy the site, understand and avoid closures and negativities worth reading the Stack Overflow Survival Guide in English.

2 answers

2

As each element a contains a href and within each a there is a p, we can assume that the variable key, used in the position of p in the loop for, can also be used to define the position of a. And that’s true because if there is a, within it there is a p determined.

It may have been a bit confusing, but you can use the variable key in the loop for both to access a position in p how much in a. This is possible because key starts at 0 and goes to the total number of elements in p, which is the same number of elements in a.

var p = Array.prototype.slice.call(document.querySelectorAll("[class='h6']")).map(function(x){return x.innerHTML});
var a = Array.prototype.slice.call(document.querySelectorAll("[class='link']")).map(function(y){return y.href});

var people = [];
for (var key in p) {
    if (p.hasOwnProperty(key) && a.hasOwnProperty(key)) {
        people.push({
            name: p[key],
            url: a[key]
          })
        console.log(people[key])
    }
}
<a class="link" href="url1.html"><p class="h6">Teste 1</p></a>
<a class="link" href="url2.html"><p class="h6">Teste 2</p></a>
<a class="link" href="url3.html"><p class="h6">Teste 3</p></a>
<a class="link" href="url4.html"><p class="h6">Teste 4</p></a>
<a class="link" href="url5.html"><p class="h6">Teste 5</p></a>

  • 2

    Thanks for the answer, Lucas! The @hkotsubo answer is very practical indeed, and thinking about the specific problem of joining two arrays, your answer fits very well as the solution to the post’s title question. Thanks! I changed the answer to that of hkotsubo because it answers with other ideas that, besides uniting the two arrays (my initial doubt), solve my initial problem in a simpler way compared to what I had imagined at first. But thanks anyway, man! Thanks a lot!

2


If the structure at all times is this, with the paragraphs inside the tags a, then you don’t need to build two arrays to then make one loop in both.

Just search for tags only p and access the a through property parentNode. And to specifically search by class name, you can use getElementsByClassName (it’s not that it’s "better," it’s just to show an alternative to querySelectorAll).

And to do the loop by elements, no need to create an array with slice. If you will not need this array later and will only use it in loop, just use for..of:

let people = [];
for (const p of document.getElementsByClassName("h6")) {
    people.push({ name: p.innerHTML, url: p.parentNode.href });
}
console.log(people);
<a class="link" href="url1.html"><p class="h6">Teste 1</p></a>
<a class="link" href="url2.html"><p class="h6">Teste 2</p></a>
<a class="link" href="url3.html"><p class="h6">Teste 3</p></a>
<a class="link" href="url4.html"><p class="h6">Teste 4</p></a>
<a class="link" href="url5.html"><p class="h6">Teste 5</p></a>

This solution works if each p is the immediate son of tag a.


Or, you can do the opposite: search by tags a and from them seek by the paragraph:

let people = [];
for (const a of document.getElementsByClassName("link")) {
    // busca pelo parágrafo a partir da tag "a"
    let p = a.querySelector('p[class="h6"]');
    people.push({ name: p.innerHTML, url: a.href });
}
console.log(people);
<a class="link" href="url1.html"><p class="h6">Teste 1</p></a>
<a class="link" href="url2.html"><p class="h6">Teste 2</p></a>
<a class="link" href="url3.html"><p class="h6">Teste 3</p></a>
<a class="link" href="url4.html"><p class="h6">Teste 4</p></a>
<a class="link" href="url5.html"><p class="h6">Teste 5</p></a>

Notice that a.querySelector('p[class="h6"]') search from the tag a (and not of document), so I guarantee I’ll only get by the tag p whose class is "H6" that is within this tag.

This solution is more general because the p does not necessarily need to be an immediate child of a: it can be on any level below. Ex:

let people = [];
for (const a of document.getElementsByClassName("link")) {
    // busca pelo parágrafo a partir da tag "a"
    let p = a.querySelector('p[class="h6"]');
    people.push({ name: p.innerHTML, url: a.href });
}
console.log(people);
<a class="link" href="url1.html">
  <div>bla
    <div>bla
      <p class="h6">Teste 1</p>
    </div>
  </div>
</a>


If you really want to use arrays

I already said in the comments that I would not need to create the arrays, but if the idea is to use them, there are some considerations to be made.

According to the documentation, the use of for..in nay is recommended to go through arrays. This is because the for..in does not guarantee the order of the elements, in addition to other problems cited here.

Of course some browsers can return the elements in order, but this is not guaranteed (and even so, it is worth paying attention to the link already quoted). Obviously if the order is not important and the problems of the link already mentioned do not happen, there would be no problem in using for..in. But if you want to ensure order, an alternative is to iterate the arrays indexes directly, using the for "traditional".

In the code below I also show 2 different ways to get the arrays: with Array.from and with spread syntax (I don’t think they’re better or worse than slice, is just to show other ways to do).

// alternativas à slice
var p = Array.from(document.querySelectorAll("[class='h6']")).map(function(x) { return x.innerHTML });
var a = [...document.querySelectorAll("[class='link']")].map(function(y) { return y.href });

let people = [];
let tamanho = Math.min(a.length, p.length); // pega o tamanho do menor array
for (let i = 0; i < tamanho; i++) {
    people.push({ name: p[i], url: a[i] });
}
console.log(people);
<a class="link" href="url1.html"><p class="h6">Teste 1</p></a>
<a class="link" href="url2.html"><p class="h6">Teste 2</p></a>
<a class="link" href="url3.html"><p class="h6">Teste 3</p></a>
<a class="link" href="url4.html"><p class="h6">Teste 4</p></a>
<a class="link" href="url5.html"><p class="h6">Teste 5</p></a>

I also did a treatment in case the arrays are different sizes, in which case the for only goes until the smallest of arrays is finished. So you don’t need to use hasOwnProperty, because I am accessing indexes that surely exist in both (and are only the numerical indexes, there is no risk to bring other properties, as can occur with for..in).

Of course in your case they have equal sizes, because the structure of HTML ensures this (each a has its respective p) - but if the structure already guarantees this, I insist again that the arrays would not be necessary and the solutions proposed above are simpler and straightforward (unless, of course, you need to use the arrays to do other things later, then it would make sense to create them).

  • Although it’s good practice what you described, it doesn’t answer the question. The question only questions how to fill an object vector, where each object is built using values of two different vectors.

  • 2

    @Lucassamuel Sorry, but my understanding was another. He wants to fill the object with the text of the paragraphs and the respective links. The way he tried to solve was building 2 arrays and trying to travel them at the same time, but I do not think it is the best solution, so I said that this was not necessary and suggested another way. I mean, it’s the typical case of XY problem

  • 2

    @Lucassamuel If the structure of HTML were another, with paragraphs and links with no relation between them, then yes I agree that the only way would be to build the 2 arrays and go through them at the same time. But as he gave an example of HTML, I suggested a solution that I think is best. Anyway, I always prefer to give a solution that I believe is better rather than insist on one that I find worse

  • @Lucassamuel and hkotsubo, thank you so much for the comments! All your thoughts have helped me a lot! Thanks to both of you!

  • Hkotsubo, I will accept @Lucassamuel’s answer because his answer is more related to what I originally asked. However, what you wrote opened my eyes a lot! In fact, I caused an XY problem, and you suggested me a simpler way to solve my problem with a very good solution! From now on, I will try to ask clearer questions here in the OS. Thank you so much for the answer too, man! Thanks!

  • 1

    @winiercape If you recognize that the question is XY, just edit it. Something like, "I need to do X, I tried Y, but the result was A, only it should be B. Can you do Y or is there another way?" - so focus more on X and not Y. Anyway, I still prefer not to create the 2 arrays, it seems a very big turn for what you want to do - unless, of course, you need the elements to do other things later, then it would be worth having the arrays

  • @winiercape I updated the answer with some details about using for..in and an alternative to joining the 2 arrays, I hope it helps

  • 1

    Thank you, hkotsubo! Discussion here became interesting, and it was profitable for me to read the considerations of both. I changed the answer, my dear. Thank you again!

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.