简体   繁体   中英

Sort a 2D Array/Grid/Table of items in Javascript

I have an inventory of items in my game and the player will need to have the ability to auto-sort the items based on several criteria being name,quantity and type.

 // create the Inventory grid var InventoryWidth = 2; var InventoryHeight = 4; var Inventory = new Array(InventoryWidth); for (var i = 0; i < InventoryWidth; i++) { Inventory[i] = new Array(InventoryHeight); } // set the Items & default quantities Inventory[0][0] = "Potion"; Inventory[1][0] = 2; Inventory[0][1] = "Elixir"; Inventory[1][1] = 9; Inventory[0][2] = "Antidote"; Inventory[1][2] = 5; Inventory[0][3] = "Ether"; Inventory[1][3] = 1; // function for sorting items function Sort2D(array2D, byColumn, ascending) { // sort, seems I am using the wrong sorting function or my approach is wrong here: // not sure how to do ASC/DESC as well array2D.sort(function(a, b) { if(a[0] === b[0]) { var x = a[byColumn].toLowerCase(), y = b[byColumn].toLowerCase(); return x < y ? -1 : x > y ? 1 : 0; } return a[0] - b[0]; }); } // sort all rows by first column: "name", setting to 1 should compare and sort the quantities instead Sort2D( Inventory, 0, true); // print grid contents var output = ""; for(var i = 0; i < InventoryHeight; i++) { if (i == 0) { output += " | name | own |"; } for(var j = 0; j < InventoryWidth; j++) { if (j == 0) { output += "\\n"+i+"|"; } output+=Inventory[j][i]; if (j >= Inventory[0].length-1) { output += "|\\n"; } else { output += ", "; } } } console.log(output); 

However I can't seem to figure out how to sort the grid like a table of items. I'd need it to sort the row order by a chosen column and the ability to have it in ASC/DESC order. How would I go about this?

To sort an array alphabetically, you just need to use the localeCompare method. Numbers have their own version and that can be confusing, so we coerce the variable before comparing it.

function sortAlphabetically(a, b) {
    return String(a).localeCompare(b);
}

["cat", "apple", "dog", "beef"].sort(sortAlphabetically);
// -> ["apple", "beef", "cat", "dog"]

I think the main problem you're having is actually with the way you've created your array. At the moment, your array looks like this:

var inventory = [
    ["Potion", "Elixir", "Antidote", "Ether"],
    [2, 9, 5, 1]
];

That means there's no association between "Potion" and 2 , other than the array indicies. I think you'll have much better luck if you adjust the array to look like this.

var inventory = [
    ["Potion", 2],
    ["Elixir", 9],
    ["Antidote", 5],
    ["Ether", 1]
];

Sorting that is much easier. As a bonus, running the .concat() method will clone the array before trying to sort it so the original data isn't modified and having the function return the data in ascending order by default is more conventional.

function sort2D(array, byColumn, isDescending) {

    var sorted = array.concat().sort(function (a, b) {

        return typeof a[byColumn] === "string"
            ? sortAlphabetically(a[byColumn], b[byColumn])
            : a[byColumn] - b[byColumn];

    });

    return isDescending
        ? sorted.reverse()
        : sorted;

}

sort2D(inventory, 0);
// -> [ ["Antidote", 5], ["Elixir", 9], ["Ether", 1], ["Potion", 2] ]
sort2D(inventory, 0, true);
// -> [ ["Potion", 2], ["Ether", 1], ["Elixir", 9], ["Antidote", 5] ]
sort2D(inventory, 1);
// -> [ ["Ether", 1], ["Potion", 2], ["Antidote", 5], ["Elixir", 9] ]

I hope that helps.

Update: Logging out your information becomes easier as well:

var output = inventory
    .map(function (inv) {
        return "| " + inv.join(" | ") + " |";
    })
    .join("\n");
console.log("| name | own |\n" + output);

Update 2: Here's how to sort the old data.

function sort2D(array, byColumn, isDescending) {

    // Step 1: sort the part of the array you're trying to sort.

    var preSort = array[byColumn].concat().sort(function (a, b) {

        return typeof a === "string"
            ? sortAlphabetically(a, b)
            : a - b;

    });

    if (isDescending) {
        preSort = preSort.reverse();
    }

    // Step 2: create a new, sorted array with your sorted column.

    var sorted = [];
    sorted[byColumn] = preSort;

    // Step 3: create a map to show how the array way sorted.

    var sortMap = {};
    preSort.forEach(function (item, i) {
        sortMap[array[byColumn].indexOf(item)] = i;
    });

    // Step 4: manually sort the other items of the array.

    array.forEach(function (info, i) {

        var copy = [];

        if (i !== byColumn) {

            info.forEach(function (item, j) {
                copy[sortMap[j]] = item;
            });

            sorted[i] = copy;

        }

    });

    // Step 5: return the newly sorted array.

    return sorted;

}

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