按多个属性对多维数组进行排序

时间:2016-04-26 10:56:05

标签: javascript arrays sorting multidimensional-array

我试图通过多个属性对数组进行排序,但问题是我的数组是多维的。 目前我已经建立了这个:

// Private function to get the value of the property
var _getPropertyValue = function (object, notation) {

    // Get all the properties
    var properties = notation.split('.');

    // If we only have one property
    if (properties.length === 1) {

        // Return our value
        return object[properties];
    }

    // Loop through our properties
    for (var property in object) {

        // Make sure we are a property
        if (object.hasOwnProperty(property)) {

            // If we our property name is the same as our first property
            if (property === properties[0]) {

                // Remove the first item from our properties
                properties.splice(0, 1);

                // Create our new dot notation
                var dotNotation = properties.join('.');

                // Find the value of the new dot notation
                return _getPropertyValue(object[property], dotNotation);
            }
        }
    }
};

// Create a service
var service = {

    // Sorts our products
    sort: function (products, notation) {

        notation = notation || 'details.title';

        // Call sort
        products.sort(function (a, b) {

            // Get our values
            var aValue = _getPropertyValue(a, notation),
                bValue = _getPropertyValue(b, notation);

            console.log(bValue);

            // If our attribute name is not the same as the second attribute
            if (aValue <= bValue) {

                // Return -1
                return -1;
            }

            // Otherwise return 1
            return 1;
        });
    }
};

// Return our service
return service;

这是阵列(产品)中的一个项目

{
    "id": 1,
    "gtin": "8714574627946|4549292038446",
    "productId": "0592C022",
    "make": "Canon",
    "model": "750D + EF-S 18-55mm",
    "expert": false,
    "sponsored": false,
    "attributes": {
        "id": 1,
        "compatibleMemory": "SD, SDHC, SDXC\"",
        "whiteBalance": "ATW, Cloudy, Custom modes, Daylight, Flash, Fluorescent L, Shade, Tungsten\"",
        "sceneModes": "Food, Landscape, Sports\"",
        "shootingModes": "",
        "photoEffects": "",
        "cameraPlayback": "Movie, Single image, Slide show\"",
        "tripod": false,
        "directPrinting": false,
        "colour": "Black",
        "picture": {
            "id": 1,
            "megapixel": "24.2 MP",
            "type": "SLR Camera Kit",
            "sensorType": "CMOS",
            "maxResolution": "6000 x 4000 pixels",
            "resolutions": "3984x2656, 2976x1984, 1920x1280, 720x480, 5328x4000, 3552x2664, 2656x1992, 1696x1280, 640x480, 6000x3368, 3984x2240, 2976x1680, 1920x1080, 720x480, 4000x4000, 2656x2656, 1984x1984, 1280x1280, 480x480\"",
            "stablizer": true,
            "location": "Lens",
            "supportedAspectRatios": "2.9 cm",
            "totalMegapixels": "24.7 MP",
            "formats": "JPG"
        },
        "video": {
            "id": 1,
            "maxResolution": "1920 x 1080 pixels",
            "resolutions": "640 x 480, 1280 x 720, 1920 x 1080 pixels\"",
            "captureResolution": "",
            "frameRate": "",
            "fullHD": true,
            "supportedFormats": null
        },
        "audio": {
            "id": 1,
            "supportedFormats": ""
        },
        "battery": {
            "id": 1,
            "powerSource": "Battery",
            "technology": "Lithium-Ion (Li-Ion)",
            "life": "",
            "type": "LP-E17"
        },
        "dimensions": {
            "id": 1,
            "width": "",
            "depth": "7.78 cm",
            "height": "10.1 cm",
            "weight": "",
            "weightIncludingBattery": "555 g"
        },
        "display": {
            "id": 1,
            "type": "LCD",
            "diagonal": "7.62 cm (3\"\")\"",
            "resolution": "1040000 pixels"
        },
        "exposure": {
            "id": 1,
            "isoSensitivity": "100, 6400, 12800, Auto\"",
            "mode": "Auto, Manual\"",
            "correction": "�5EV (1/2; 1/3 EV step)",
            "metering": "Centre-weighted, Evaluative (Multi-pattern), Partial, Spot\"",
            "minimum": 100,
            "maxiumum": 12800
        },
        "flash": {
            "id": 1,
            "modes": "Hi-speed sync, Red-eye reduction\"",
            "exposureLock": true,
            "rangeWide": "",
            "rangeTelephoto": "",
            "rechargeTime": "",
            "speed": "1/200"
        },
        "focusing": {
            "id": 1,
            "focus": "TTL-CT-SIR",
            "adjustment": "",
            "autoFocusModes": "",
            "closestDistance": "0.25 m",
            "normalRange": "",
            "macroRangeTelephoto": "",
            "macroRangeWide": "",
            "autoModeTelephoto": "",
            "autoModeWide": ""
        },
        "interface": {
            "id": 1,
            "pictBridge": true,
            "usbVersion": "2.0",
            "usbType": "",
            "hdmi": true,
            "hdmiType": "Mini"
        },
        "lens": {
            "id": 1,
            "focalLength": "18 - 55 mm",
            "minimumFocalLength": "2.9 cm",
            "maximumFocalLength": "8.8 cm",
            "minimumAperture": "3.5",
            "maximumAperture": "38",
            "lensStructure": "13/11",
            "zoom": {
                "id": 1,
                "optical": "",
                "digital": "",
                "extraSmart": "",
                "combined": ""
            }
        },
        "network": {
            "id": 1,
            "wiFi": false,
            "wiFiStandards": "",
            "nfc": false
        },
        "shutter": {
            "id": 1,
            "fastestSpeed": "1/4000 s",
            "slowestSpeed": "30 s"
        }
    },
    "details": {
        "id": 1,
        "title": "Canon EOS 750D + EF-S 18-55mm",
        "description": "\"<b>Take your pictures to the next level with EOS 750D</b>\\n- Effortlessly take your pictures to the next level with the latest DSLR technology and Scene Intelligent Auto mode.\\n- Effortlessly capture stunning detail in any situation\\n- Record cinematic movies as easily as you shoot stills\\n- Easily connect and share your images with the world\\n\\n<b>Take your pictures to the next level with EOS 750D</b>\\n<b>Range of shooting modes</b>\\nEffortlessly capture stunning images using the latest DSLR technology with Basic and Creative modes, which allow you to take as much or as little control as you like.\\n\\n<b>Moveable screen for creative framing</b>\\nExplore creative shooting angles and enjoy simple and intuitive access to controls using the 3.0\"\" (7.7cm) Vari Angle LCD touch screen\\n\\n<b>Intelligent Viewfinder</b>\\nEOS 750D features an Intelligent Viewfinder which gives a much enhanced shooting experience. As you look through the viewfinder you can more easily see the focus point and any active AF areas, also the shooting information is clearly displayed.\\n\\n<b>Effortlessly capture stunning detail in any situation</b>\\nCapture vivid, detailed, high-resolution images with better dynamic range, lower noise and excellent control over depth of field thanks to a 24.2 Megapixel APS-C sensor.\\n\\n<b>19 all cross-type AF points for accurate subject tracking</b>\\nKeep track of fast moving action thanks to a fast and accurate autofocus system comprising 19 cross-type AF points.\\n\\n<b>Fast processor for action</b>\\nA powerful DIGIC 6 processor delivers full resolution shooting at 5 fps � so you�ll never miss that decisive moment.\\n\\n<b>Great low light shots</b>\\nTake memorable low light pictures without using flash thanks to a large ISO sensitivity range of ISO 100-12800 (extendable to ISO 25600)\\n\\n<b>Record cinematic Full HD movies as easily as you shoot stills</b>\\nShoot superbly detailed Full HD movies with a cinematic feel thanks to DSLR control over depth of field. Record your movies in MP4 format for quicker online sharing and easier transfer to other devices.\\n\\n<b>Smoother results</b>\\nEasily shoot cinematic Full HD movies with Hybrid CMOS AF III to track movement and focus smoothly between subjects.\\n\\n<b>Empower your creativity with easy shooting modes</b>\\nLet the camera do the work for you and capture creative photos with ease using a range of Scene Modes\\n\\n<b>Creative movie modes</b>\\nExpand the range of shooting possibilities in movies with features like Miniature Effect in movie.\"",
        "shortDescription": "\"22.3 x 14.9mm CMOS, 24.2 megapixels, 3:2, DIGIC 6, LCD, ISO 12800, Full HD Movie, USB, HDMI mini, SD/SDHC/SDXC, Black\"",
        "summary": "\"Canon 750D + EF-S 18-55mm, EOS. Megapixel: 24.2 MP, Camera type: SLR Camera Kit, Sensor type: CMOS. Focal length range (f-f): 18 - 55 mm, Minimum focal length (35mm film equiv): 2.9 cm, Maximum focal length (35mm film equiv): 8.8 cm. Focus: TTL-CT-SIR, Closest focusing distance: 0.25 m. ISO sensitivity: 100, 6400, 12800, Auto, Light exposure modes: Auto, Manual, Light exposure control: Program AE. Fastest camera shutter speed: 1/4000 s, Slowest camera shutter speed: 30 s, Camera shutter type: Electronic\"",
        "shortSummary": "\"Canon EOS 750D + EF-S 18-55mm, ATW, Cloudy, Custom modes, Daylight, Flash, Fluorescent L, Shade, Tungsten, Food, Landscape, Sports, Movie, Single image, Slide show, Battery, SLR Camera Kit, TTL-CT-SIR\""
    },
    "category": null,
    "preview": {
        "id": 1,
        "highRes": "http://images.icecat.biz/img/norm/high/26171112-1991.jpg",
        "lowRes": "http://images.icecat.biz/img/norm/low/26171112-1991.jpg",
        "manual": ""
    }
}

这适用于1个属性。有谁知道如何有效重新使用多个属性?

我试过这样做:

// Create a service
var service = {

    // Sorts our products
    sort: function (products, notations) {

        // Call sort
        products.sort(function (a, b) {

            // For each notation
            for (var i = 0; i < notations.length; i++) {

                // Get our notation
                var notation = notations[i];

                // Get our values
                var aValue = _getPropertyValue(a, notation),
                    bValue = _getPropertyValue(b, notation);

                console.log(bValue);

                // If our attribute name is not the same as the second attribute
                if (aValue <= bValue) {

                    // Return -1
                    return -1;
                }

                // Otherwise return 1
                return 1;
            }
        });
    }
};

并像这样调用它:

handler.sort(self.products, ['attributes.dimensions.weightIncludingBattery', 'attributes.network.wiFi']);

但这似乎只是按第一个属性而不是第二个属性排序。

3 个答案:

答案 0 :(得分:1)

通过@Nina Scholz发布的链接,我设法创建了一组似乎快速运行的功能。这组函数如下所示:

// Private function to get the value of the property
var _getPropertyValue = function (object, notation) {

    // Get all the properties
    var properties = notation.split('.');

    // If we only have one property
    if (properties.length === 1) {

        // Return our value
        return object[properties];
    }

    // Loop through our properties
    for (var property in object) {

        // Make sure we are a property
        if (object.hasOwnProperty(property)) {

            // If we our property name is the same as our first property
            if (property === properties[0]) {

                // Remove the first item from our properties
                properties.splice(0, 1);

                // Create our new dot notation
                var dotNotation = properties.join('.');

                // Find the value of the new dot notation
                return _getPropertyValue(object[property], dotNotation);
            }
        }
    }
};

// Get our fields
var _getFields = function (notations) {

    // Create our array
    var fields = [];

    // For each notation
    angular.forEach(notations, function (notation) {

        // Get our field
        var names = notation.split('.'),
            len = names.length,
            name = names[len - 1];

        // Push our name into our array
        fields.push({ name: name, notation: notation });
    });

    // Return our fields
    return fields;
};

// Create a mapped array
var _createMapped = function (array, notations) {

    // Get our fields
    var fields = _getFields(notations);

    // Create our mapped array
    var mapped = array.map(function (a, i) {

        // Create our object
        var obj = {
            index: i
        };

        // For each of our fields
        angular.forEach(fields, function (field) {

            // Map our field
            obj[field.name] = _getPropertyValue(a, field.notation);
        });

        // Return our object
        return obj;
    });

    // Return our mapped array
    return mapped;
};

// Create a service
var service = {

    // Sorts our products
    sort: function (products, notations) {

        // Get our fields
        var mapped = _createMapped(products, notations);

        // Sort our mapped array
        mapped.sort(function (a, b) {

            // Loop through our properties
            for (var i = 0; i < notations.length; i++) {

                // Get our value (skip the first)
                var o1 = a[i + 1];
                var o2 = b[i + 1];

                // Compare the values
                if (o1 < o2) return -1;
                if (o1 > o2) return 1;
            }

            // Default return 
            return 0;
        });

        // Get our result
        var result = mapped.map(function (item) {
            return products[item.index];
        });

        // Return our result
        return result;
    }
};

// Return our service
return service;

答案 1 :(得分:0)

可以按照以下示例

对多个属性进行排序

&#13;
&#13;
var data = [
	        {
	          a : 10,
	          b : 24
            },
	        {
	          a : 11,
	          b : 20
            },
	        {
	          a : 12,
	          b : 21
            },
	        {
	          a : 12,
	          b : 10
            },
	        {
	          a : 10,
	          b : 12
            },
	        {
	          a : 15,
	          b : 7
            },
	        {
	          a : 10,
	          b : 18
            }
           ]
var sortData = (arr, prop1, prop2) => arr.sort((p,c) => p[prop1] < c[prop1] ? -1: p[prop1] == c[prop1] ? p[prop2] <= c[prop2] ? -1 : 1: 1);
      sorted = sortData(data,"a","b");

document.write("<pre>" + JSON.stringify(sorted,null,2) + "</pre>");
&#13;
&#13;
&#13;

答案 2 :(得分:0)

基本上你需要这样的东西:

对于属性值的访问,通过对象

进行迭代
function getValue(string, object) {
    return string.split('.').reduce(function (r, a) {
        return r[a];
    }, object);
}

对于排序机制,迭代所需的排序参数。实际上我假设所有的值都是字符串。

// handler.sort
function sort(array, order) {
    array.sort(function (a, b) {
        var r = 0;
        order.some(function (s) {
            r = getValue(s, a).localeCompare(getValue(s, b));
            return r;
        });
        return r;
    });
}

这样做的缺点是排序非常慢,因为特定值的查找机制。

更快的方式是sorting with map,其中地图仅包含getValue

中的所需值