3
\$\begingroup\$

I'm fairly new to coding and am trying to learn more about best practices. I wanted to have an nestedArray of objectArrays, and I wanted to be able to sort the elements in each objectArray based on matching certain property values with some in the preceding objectArray. This is what I came up with (below).

It works, but I'm not sure if there are more succinct or clearer ways of writing it. They are not intended to be grouped in alphabetical order or anything, eventually the names will be uuid's.

If you were to re-write the sortArray function using best practices, what would you change? Should it be terser?

const nestedArray =[
  [  // arr 0
     { parent: "", name:"chad"}
    ,{ parent: "", name:"jessica"}
    ,{ parent: "", name:"louise"}
  ],
  [  // arr 1
     { parent: "chad", name:"gerald"} 
    ,{ parent: "jessica", name:"hamster" }
    ,{ parent: "louise", name:"billy"}
    ,{ parent: "louise", name:"Franklina"}
    ,{ parent: "chad", name:"curbiboi"}
    ,{ parent: "chad", name:"mnyarh"}
  ],  
  [  // arr 2
     { parent: "Franklina", name:"gerald"} 
    ,{ parent: "mnyarh", name:"billy"}
    ,{ parent: "Franklina", name: "turmeric"}
  ]
];

console.log("---");

function sortArray(rootArray){
  let newOuterArray = [rootArray[0]];
  for (let i = 0; i < rootArray.length-1 ; i++){
    let sortedInnerArray = []
    for (let j = 0; j < rootArray[i].length ; j++){
      let arrayFilteredByParentName = rootArray[i+1].filter(obj => obj.parent === rootArray[i][j].name)
      arrayFilteredByParentName.forEach(element => sortedInnerArray = [...sortedInnerArray, element]);
    }
    newOuterArray = [...newOuterArray, sortedInnerArray];
  }
  return newOuterArray;
}

console.log(sortArray(nestedArray));

Here's the console output:

(3) [Array(3), Array(6), Array(3)]
    0: Array(3)
    0: {parent: '', name: 'chad'}
    1: {parent: '', name: 'jessica'}
    2: {parent: '', name: 'louise'}
    length: 3
    [[Prototype]]: Array(0)
1: Array(6)
    0: {parent: 'chad', name: 'gerald'}
    1: {parent: 'chad', name: 'curbiboi'}
    2: {parent: 'chad', name: 'mnyarh'}
    3: {parent: 'jessica', name: 'hamster'}
    4: {parent: 'louise', name: 'billy'}
    5: {parent: 'louise', name: 'Franklina'}
    length: 6
    [[Prototype]]: Array(0)
2: Array(3)
    0: {parent: 'Franklina', name: 'gerald'}
    1: {parent: 'Franklina', name: 'turmeric'}
    2: {parent: 'mnyarh', name: 'billy'}
    length: 3
    [[Prototype]]: Array(0)
length: 3
[[Prototype]]: Array(0)
\$\endgroup\$
5
  • 2
    \$\begingroup\$ Can you clarify what you mean by "sort" as I see no sorting in your code? \$\endgroup\$
    – Blindman67
    Jun 11 at 14:08
  • \$\begingroup\$ I'm not using Array.sort() which I am learning, but have a look at the second inner array in the original code (labelled Arr 1). This is unsorted. But I'd like these to be ordered by having the Arr1.element.parentName matching Arr0.element.name. I don't want to have them ordered simply by parent name alphabetical order within each element. So if arr0's first element has name Chad, then I want all of Arr1's elements which have parent: "chad" at the front of the array. Then, all of Arr1's elements which have "jessica", then the ones with 'louise'. The desired output is in the Console Output. \$\endgroup\$
    – WyreZ
    Jun 12 at 5:16
  • 1
    \$\begingroup\$ Please don't modify your code after receiving answers. This potentially invalidates the answer(s) and is overall confusing for everyone reading this Q & A later. If you have a new version with major improvements, feel free to ask a new, follow up question instead. \$\endgroup\$
    – Mast
    Jun 12 at 6:50
  • \$\begingroup\$ Just in, a friend recommended I just do this: nestedArray.forEach(subarray => subarray.sort((a, b) => a.parent.localeCompare(b.parent))); ... it totally works. How about that.... \$\endgroup\$
    – WyreZ
    Jun 12 at 14:21
  • \$\begingroup\$ @WyreZ, if that solves the issue, post it as an answer and select it as the preferred answer. \$\endgroup\$
    – radarbob
    Jun 14 at 9:55

1 Answer 1

1
\$\begingroup\$

TL;DR This code does the same thing:

function sortFunctionByKey(key){
    return function(a, b){
       if (a[key] == b[key]) return 0
        return a[key] < b[key] ? -1 : 1    
    }
}

function sortNestedByKey(arr, sortFunc){
   return arr.map(nested => {
      return [...nested].sort(sortFunc)  
   }) 
}

sorted =  sortNestedByKey(nestedArray, sortFunctionByKey('parent')) 

Depending on how exactly you plan to develop your code in the future, you can choose the solution tactics. I suggested 2 approaches in one code. The benefit of such a solution is that it can be easily modified and is quickly perceived by the programmer when reading.

    const nestedArray =[
      [  // arr 0
         { parent: "", name:"chad"}
        ,{ parent: "", name:"jessica"}
        ,{ parent: "", name:"louise"}
      ],
      [  // arr 1
         { parent: "chad", name:"gerald"} 
        ,{ parent: "jessica", name:"hamster" }
        ,{ parent: "louise", name:"billy"}
        ,{ parent: "louise", name:"Franklina"}
        ,{ parent: "chad", name:"curbiboi"}
        ,{ parent: "chad", name:"mnyarh"}
      ],  
      [  // arr 2
         { parent: "Franklina", name:"gerald"} 
        ,{ parent: "mnyarh", name:"billy"}
        ,{ parent: "Franklina", name: "turmeric"}
      ]
    ];
    
    function sortFunctionByName(a, b){
        //(1) You can wrire here any logic
        if (a.name == b.name) return 0
        return a.name < b.name ? -1 : 1 
        // OR
        // (2) use some helpers
        return sortFunctionByKey('name')
    }
    
    // helper return a specific sort function
    function sortFunctionByKey(key){
        return function(a, b){
           if (a[key] == b[key]) return 0
            return a[key] < b[key] ? -1 : 1    
        }
    }
    
    function sortNestedByKey(arr, sortFunc){
       return arr.map(nested => {
          return [...nested].sort(sortFunc) // sort copy of array
       }) 
    }
    
    sorted =  sortNestedByKey(nestedArray, sortFunctionByName)   
    // OR
    sorted2 =  sortNestedByKey(nestedArray, sortFunctionByKey('name'))   
    
    console.log(sorted)
    console.log(sorted2)

Bonus: Sort sequentially by multiple keys. Strings are used to avoid any numeric restrictions (there may be too many sort fields)

function sortFunctionByKeys(keys){
    return function(a, b){
      let ac='', bc='' 
      for (const key of keys) {
        if (a[key] !== b[key]) {
          ac += a[key] < b[key] ? '0' : '1'
          bc += a[key] > b[key] ? '0' : '1'    
        } 
      }
      if (ac == bc) return 0
      return ac < bc ? -1 : 1    
    }
}

sortNestedByKey(nestedArray, sortFunctionByKeys(['parent', 'name']))  
\$\endgroup\$
4
  • \$\begingroup\$ Thanks so much Daniil! I really like how your code is a bit more modular. It didn't quite achieve what I was looking for, but it was very close and learning your method and exploring it helped me to learn a tonne and come up with some different solutions. I'll post some of the things I came up with in the OP \$\endgroup\$
    – WyreZ
    Jun 12 at 5:57
  • \$\begingroup\$ Heh, I also noticed belatedly that my example working out inferred that the sorting was based on alphabetical order if you look at the second inner array, but this is not the intention; The third array is also correct but shows the difference. \$\endgroup\$
    – WyreZ
    Jun 12 at 6:38
  • \$\begingroup\$ @WyreZ I always strive to make the code simpler, I hope I succeeded now, but there is always an opportunity to write better \$\endgroup\$ Jun 12 at 9:44
  • \$\begingroup\$ @WyreZ also I added bonus: sort sequentially by multiple keys \$\endgroup\$ Jun 12 at 12:45

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.