How can I sort an indirect array with javascript?

前端 未结 4 1608
借酒劲吻你
借酒劲吻你 2020-12-10 22:42

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.

<         


        
相关标签:
4条回答
  • 2020-12-10 23:13

    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 }
    
    0 讨论(0)
  • 2020-12-10 23:15

    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);

    0 讨论(0)
  • 2020-12-10 23:18

    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

    0 讨论(0)
  • 2020-12-10 23:27

    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>

    0 讨论(0)
提交回复
热议问题