简体   繁体   中英

How can I sort an indirect array with javascript?

In my project, I need to sort an array that contain index of an other array (it's item). I've search for many hours, but I did not find anyone with my problem.

var arr = [1, 4, 3, 4, 5, 6, 7, 8, 9];
function sorting(){
    let arr2 = [0, 1, 2, 3, 4, 5, 6, 7, 8];
    //sorting code
}

Now, I want to sort arr2, so when I loop through it with this kind of code (under this paragraph), I access arr with the index in the sorted array (arr2).

  arr[arr2[i]]

My first move was to use arr2.sort(function(a,b){arr[a] - arr[b]}, but each time the sort wasn't good. I attempt to make my own sorting function, but my problem stayed.

To summarize, I want to sort arr2 so when I loop through it, I get the value of arr in ascending (or descending) order.

EDIT I fixe this problem, but another appears, when I applied the arr2 on my html, the order mess up.

    var arr = [1, 4, 3, 4, 5, 6, 7, 8, 9];
    function sorting(){
        let arr2 = [0, 1, 2, 3, 4, 5, 6, 7, 8];
        //The sorting block code (done)
        z = document.getElementsByClassName("triable"); //this is on what I applied arr2
        for (let i = 0; i < z.length; i++){
            z[i].style.order = arr2[i]; //this line work, but doesn't correctly do what I what it to do
        }
    }

For html, I have some div with a class "triable" and the code above this need to applied a css style (order) so the div visually change of position

You need to return the delta. Otherwise the callback returns undefined for each call.

arr2.sort(function(a, b) {
    return arr[b] - arr[a];
});

For adding the right order, you need ot take the index from indices to address the right element and assign i as style order value.

 function sort() { var array = [1, 4, 3, 4, 5, 6, 7, 8, 9], z = document.getElementsByClassName("triable"); [...array.keys()].sort((a, b) => array[b] - array[a]).forEach((v, i) => z[v].style.order = i); }
 <button onclick="sort()">sort</button><br> <div style="display: flex;"> <span class="triable">1</span> <span class="triable">4</span> <span class="triable">3</span> <span class="triable">4</span> <span class="triable">5</span> <span class="triable">6</span> <span class="triable">7</span> <span class="triable">8</span> <span class="triable">9</span> </div>

functional arbitrary sort

Here's another way to approach your problem. Let's say we have some fruits and an arbitrary order we wish to sort them in -

const fruits =
  //   0        1          2        3         4 
  [ "apple", "banana", "cherry", "orange", "peach" ]
  

const order =
  [ 1, 3, 2, 0, 4 ]

We want to be able to write something like this -

fruits.sort(sortByIndex(fruits, order))

console.log(fruits)
// [ "banana", "orange", "cherry", "apple", "peach" ]
//      1         3         2         0        4

We wish up a Comparison module to handle our sorting code -

const { empty, map } =
  Comparison
  
const sortByIndex = (values = [], indexes = []) =>
  map(empty, x => indexes.indexOf(values.indexOf(x)))

Now we just have to implement Comparison -

 const Comparison = { empty: (a, b) => a < b? -1: a > b? 1: 0, map: (m, f) => (a, b) => m(f(a), f(b)) } const { empty, map } = Comparison const sortByIndex = (values = [], indexes = []) => map(empty, x => indexes.indexOf(values.indexOf(x))) const fruits = [ "apple", "banana", "cherry", "orange", "peach" ] // 0 1 2 3 4 const order = [ 1, 3, 2, 0, 4 ] console.log(fruits) // [ "apple", "banana", "cherry", "orange", "peach" ] console.log(fruits.sort(sortByIndex(fruits, order))) // [ "banana", "orange", "cherry", "apple", "peach" ]


why a module?

Implementing a Comparison module means we have a tidy place to store all of our comparison logic. We could easily implement other useful functions like reverse and concat now -

const Comparison =
  { // ...
  , concat: (m, n) =>
      (a, b) => Ordered.concat(m(a, b), n(a, b))
  , reverse: (m) =>
      (a, b) => m(b, a)
  }

const Ordered =
  { empty: 0
  , concat: (a, b) =>
      a === 0 ? b : a
  }

Now we can model complex sorting logic with ease -

const sortByName =
  map(empty, x => x.name)

const sortByAge =
  map(empty, x => x.age)

const data =
  [ { name: 'Alicia', age: 10 }
  , { name: 'Alice', age: 15 }
  , { name: 'Alice', age: 10 }
  , { name: 'Alice', age: 16 }
  ]

Sort by name then sort by age -

data.sort(concat(sortByName, sortByAge))
// [ { name: 'Alice', age: 10 }
// , { name: 'Alice', age: 15 }
// , { name: 'Alice', age: 16 }
// , { name: 'Alicia', age: 10 }
// ]

Sort by age then sort by name -

data.sort(concat(sortByAge, sortByName))
// [ { name: 'Alice', age: 10 }
// , { name: 'Alicia', age: 10 }
// , { name: 'Alice', age: 15 }
// , { name: 'Alice', age: 16 }
// ]

And effortlessly reverse any sorter. Here we sort by name then reverse sort by age -

data.sort(concat(sortByName, reverse(sortByAge)))
// [ { name: 'Alice', age: 16 }
// , { name: 'Alice', age: 15 }
// , { name: 'Alice', age: 10 }
// , { name: 'Alicia', age: 10 }
// ]

functional principles

Our Comparison module is flexible yet reliable. This allows us to write our sorters in a formula-like way -

// this...
concat(reverse(sortByName), reverse(sortByAge))

// is the same as...
reverse(concat(sortByName, sortByAge))

And similarly with concat expressions -

// this...
concat(sortByYear, concat(sortByMonth, sortByDay))

// is the same as...
concat(concat(sortByYear, sortByMonth), sortByDay)

// is the same as...
nsort(sortByYear, sortByMonth, sortByDay)

go nuts with nsort

Now let's say we want to sort by an arbitrary number of factors. For example, sorting date objects requires three comparisons: year , month , and day -

const { empty, map, reverse, nsort } =
  Comparison

const data =
  [ { year: 2020, month: 4, day: 5 }
  , { year: 2018, month: 1, day: 20 }
  , { year: 2019, month: 3, day: 14 }
  ]

const sortByDate =
  nsort
    ( map(empty, x => x.year)  // primary: sort by year
    , map(empty, x => x.month) // secondary: sort by month
    , map(empty, x => x.day)   // tertiary: sort by day
    )

Now we can sort by year , month , day -

data.sort(sortByDate)
// [ { year: 2019, month: 11, day: 14 }
// , { year: 2020, month: 4, day: 3 }
// , { year: 2020, month: 4, day: 5 }
// ]

And just as easily reverse sort by year , month , day -

data.sort(reverse(sortByDate))
// [ { year: 2020, month: 4, day: 5 }
// , { year: 2020, month: 4, day: 3 }
// , { year: 2019, month: 11, day: 14 }
// ]

Implementing N-sort is a breeze thanks to functional principles. Our concat and empty do all the hard work -

const Comparison =
  { // ...
  , nsort: (...m) =>
      m.reduce(Comparison.concat, Comparison.empty)
  }

Expand the snippet below to see this code in action -

 const Comparison = { empty: (a, b) => a < b? -1: a > b? 1: 0, map: (m, f) => (a, b) => m(f(a), f(b)), concat: (m, n) => (a, b) => Ordered.concat(m(a, b), n(a, b)), reverse: (m) => (a, b) => m(b, a), nsort: (...m) => m.reduce(Comparison.concat, Comparison.empty) } const Ordered = { empty: 0, concat: (a, b) => a === 0? b: a } const { empty, map, concat, reverse, nsort } = Comparison const sortByDate = nsort ( map(empty, x => x.year) // primary, map(empty, x => x.month) // secondary, map(empty, x => x.day) // tertiary ) const data = [ { year: 2020, month: 4, day: 5 }, { year: 2019, month: 11, day: 14 }, { year: 2020, month: 4, day: 3 } ] console.log(data.sort(reverse(sortByDate))) // [ { year: 2020, month: 4, day: 5 } //, { year: 2020, month: 4, day: 3 } //, { year: 2019, month: 11, day: 14 } // ]


JavaScript modules

Above Comparison and Ordered are defined as simple objects. JavaScript is a very flexible language and import / export syntaxes were made explicitly available for modularising your programs. Writing modules in this way gives us a clear picture of where things should go and provides us with plenty of room to grow our code -

// Comparison.js

import { lt, gt, eq, concat:_concat } from "./Ordered"

const asc = (a, b) =>
  (console.log(a, b), a < b) ? lt
    : a > b ? gt
      : eq

const empty =
  asc

const map =  (m, f) =>
  (a, b) => m(f(a), f(b))

const concat = (m, n) =>
  (a, b) => _concat(m(a, b), n(a, b))

const reverse = (m) =>
  (a, b) => m(b, a)

const desc =
  reverse(asc)

export { asc, concat, desc, empty, map, reverse }
// Ordered.js

const lt = 
  -1

const gt =
  1

const eq =
  0

const empty =
  eq

const concat = (a, b) =>
  a === eq ? b : a

export { concat, empty, eq, gt, lt }

Much Code, but it works:)

For sort ASC:

 var test = [1, 4, 3, 4, 5, 6, 7, 8, 9]; console.log("Original Array: " + test); var len = test.length; var indices = new Array(len); for (var i = 0; i < len; ++i) indices[i] = i; indices.sort(function (a, b) { return test[a] < test[b]? -1: test[a] > test[b]? 1: 0; }); test.sort(); console.log("Sort-ASC " + test); console.log("Index from Array " + indices);

For sort DESC:

 var test = [1, 4, 3, 4, 5, 6, 7, 8, 9]; console.log("Originales Array: " + test) var len = test.length; var indices = new Array(len); for (var i = 0; i < len; ++i) indices[i] = i; indices.sort(function (a, b) { return test[a] < test[b]? -1: test[a] > test[b]? 1: 0; }); indices.reverse(); test.sort(); test.reverse(); console.log("Sort-DESC " + test); console.log("Index from Array " + indices);

Its much easy buddy use this arr.sort(function(a, b){return a - b}); // use return otherwise it will not triggered and - + plus denote ascndng dcndng ordee Simple method..... Happy coding

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM