strategically placing array elements in a div

Viewed 69

I have an array with a list of objects. What i'm trying to achieve is I want to read every object in the array and append the value to a div by following certain rules. The rules are: First, read the key of the object, for example, 1st object is {1: 'test_12'} you have to read the key which is 1. Second, get the value of that key. Third, append it to div top or div bottom. Now here is where it gets a little complicated. When you append it to the divs its placement should be strategic I want to have 5 of the object values on div top and the other 5 on div bottom. Now the objects with keys 1 and 2 are not equal. When you append their values, they should be placed without having two values with the same keys next to each other. Now as I mentioned the objects with keys 1 and 2 are not equal so there are going to be some values appended to the divs that are going to end up next to each other but the goal is to reduce that to the maximum possible. How can I achieve this? Thanks in advance.

NOTE1: Please run the code first and take a look at how the 2 divs (top & bottom) elements are placed. They are placed strategically so that it will show you what I want the final product to look like.

NOTE2: I have added a rough js sketch with comments to show what I'm trying to achieve.

NOTE3: I want the solution to work with any array length and should not only be limited to this question's array length!

const myArray = 
  [ { 1: 'test_12' } 
  , { 2: 'test_13' } 
  , { 2: 'test_14' } 
  , { 1: 'test_15' } 
  , { 2: 'test_16' } 
  , { 2: 'test_17' } 
  , { 2: 'test_18' } 
  , { 1: 'test_19' } 
  , { 1: 'test_20' } 
  , { 2: 'test_21' } 
  ] 

let newArray = []

//something like this (this is just a very rough sketch!!)
myArray.forEach((obj) => {
  Object.keys(obj).forEach((key) => {
    //if the newArray is empty push a random array to it
    if (newArray.length == 0) {
      newArray.push(myArray[(Math.random() * myArray.length) | 0])
    }
    //get the last element in the newArray and check if its key is 1 or 2
    else if (Object.keys(newArray.at(-1))[0] == 1) {
      //get a random object from myArray with key 2 and push it to newArray
      //if none are found push what ever object you find
    } else if (Object.keys(newArray.at(-1))[0] == 2) {
      //get a random object from myArray with key 1 and push it to newArray
      //if none are found push what ever object you find
    }

    //once looped through every myArray objects and newArray is fully constructed get every element from newArray and append the first 5 objects value to div top and the last 5 objects value  to div bottom
    newArray.slice(0, 5).forEach((obj) => {
      Object.keys(obj).forEach((key) => {
        $('.top').html(`<p>${obj[key]}</p>`)
      });
    });
    //for the last 5 newArray elements
    newArray.reverse().slice(0, 5).reverse().forEach((obj) => {
      Object.keys(obj).forEach((key) => {
        $('.bottom').html(`<p>${obj[key]}</p>`)
      });
    });
  });
});
.top {
  display: flex;
  flex-direction: row;
  justify-content: space-evenly;
  width: 100%;
  height: 3em;
  background-color: pink;
}

.bottom {
  display: flex;
  flex-direction: row;
  justify-content: space-evenly;
  width: 100%;
  height: 3em;
  background-color: gold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<!--I want the final product to be something like this-->
<div class="top">
  <p>test_12</p>
  <p>test_13</p>
  <p>test_21</p>
  <p>test_19</p>
  <p>test_16</p>
</div>
<div class="bottom">
  <p>test_18</p>
  <p>test_15</p>
  <p>test_14</p>
  <p>test_17</p>
  <p>test_20</p>
</div>

1 Answers

In bellow code the input array is sored as match as possible and return two arrays. One with sorted element with different keys, Other with all remained unique keys. I merged the arrays to slice them with 5 items for topArray and bottomArray. you can modify it based on your need.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>test</title>
</head>

<body>
  <style>
    .top {
      display: flex;
      flex-direction: row;
      justify-content: space-evenly;
      width: 100%;
      height: 3em;
      background-color: pink;
    }

    .bottom {
      display: flex;
      flex-direction: row;
      justify-content: space-evenly;
      width: 100%;
      height: 3em;
      background-color: gold;
    }
  </style>

  <!--I want the final product to be something like this-->
  <div class="top">
    <p>test_12</p>
    <p>test_13</p>
    <p>test_21</p>
    <p>test_19</p>
    <p>test_16</p>
  </div>
  <div class="bottom">
    <p>test_18</p>
    <p>test_15</p>
    <p>test_14</p>
    <p>test_17</p>
    <p>test_20</p>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

  <script>
    const myArray = [{
        1: 'TEST_12'
      },
      {
        2: 'TEST_13'
      },
      {
        2: 'TEST_14'
      },
      {
        1: 'TEST_15'
      },
      {
        2: 'TEST_16'
      },
      {
        2: 'TEST_17'
      },
      {
        2: 'TEST_18'
      },
      {
        1: 'TEST_19'
      },
      {
        1: 'TEST_20'
      },
      {
        2: 'TEST_21'
      }
    ];

    function sortByKey(Arr, srt = []) {
      let newArr = []
      for (let i = 0; i < Arr.length; i++) {
        if (srt.length == 0) {
          srt.push(Arr[i])
        } else if (Object.keys(srt.at(-1))[0] !== Object.keys(Arr[i])[0]) {
          srt.push(Arr[i])
        } else {
          newArr.push(Arr[i])
        }
      }

      if (newArr.some(obj => obj.hasOwnProperty(Object.keys(srt.at(-2))[0]))) {
        return (sortByKey(newArr, srt));
      }
      return [srt, newArr];
    }

    let [sorted, singleKey] = sortByKey(myArray);
    
    let topArray = bottomArray = [...sorted,...singleKey]

    $('.top').html(``)
    topArray.slice(0, 5).forEach((obj) => {
      Object.keys(obj).forEach((key) => {
        $('.top').append(`<p>${obj[key]}</p>`)
      });
    });
    //for the last 5 newArray elements
    $('.bottom').html(``)
    bottomArray.reverse().slice(0, 5).reverse().forEach((obj) => {
      Object.keys(obj).forEach((key) => {
        $('.bottom').append(`<p>${obj[key]}</p>`)
      });
    });
  </script>
Related