简体   繁体   中英

Backbone.js: compare model attributes in a collection

I have a collection of unlimited scope (can be 0, can be 1000, can be a million). I need to search the attributes of every model in the collection and return the attributes (and their values) that are the same.

For example, if I have the following three models in the collection:

modelOne:
  color: "red"
  age: 10
  size: "large"

modelTwo:
  color: "red"
  age: 11
  size: "medium"

modelThree:
  color: "red"
  age: 9
  size: "large"

I need the app to return color: "red" (or some other derivation that can be parsed), since it is the only attribute that is equal across all three models.

Edit John Munsch's solution worked very well, but now the requirements have changed in that some attributes can now be arrays. Is there a way to compare regular attributes, and attributes that are arrays?

New code example:

modelOne:
  color: "red"
  age: 10
  sizes: ["small", "large"]

modelTwo:
  color: "red"
  age: 9
  sizes: ["small", "large"]

Here's a quick jsFiddle with my version of an answer : http://jsfiddle.net/JohnMunsch/3NMGD/

Note: Both the jsFiddle and the code below have been updated to reflect the changed requirements of the question.

var model = [
    {
      color: "red",
      age: 10,
      size: [ "small", "large" ]
    },
    {
      color: "red",
      age: 11,
      size: [ "small", "large" ]
    },
    {
      color: "red",
      age: 9,
      size: [ "small", "large" ]
    }
];

function findCommonalities(data) {
    if (data.length > 0) {
        // It's safe enough to get the list of keys from the very first
        // element. If the later ones differ, you know that the keys they
        // had but the first element didn't are guaranteed not to be in
        // the common set anyway because the first element didn't
        // have them.
        var keys = _.keys(data[0]);
        var commonalities = { };

        _.each(keys,
            function (key) {
                var values = _.pluck(data, key);

                if (values.length == data.length) {
                    // Sadly calling _.uniq() won't work when the values
                    // plucked out are arrays themselves. It calls ===
                    // and that's not sufficient for arrays.
                    if (_.isArray(values[0])) {
                        // However, we can get a little tricky here.
                        // What if we _.zip() together all of the arrays
                        // (assuming the ordering for each array is the
                        // same) then we'll end up with an array of
                        // arrays where each one can again be tested
                        // with _.uniq() because each one will contain
                        // the same value taken from each array.
                        var zippedValues = _.zip(values);
                        console.log("zippedValues", zippedValues);

                        if (!_.find(zippedValues,
                            function (zippedValue) {
                                var uniqueValues = _.uniq(zippedValue);

                                // Note: This test is the inverse of the
                                // one below. We're trying to find any
                                // array that has more than one value in
                                // it. If we do then there's some
                                // variance.
                                return uniqueValues.length != 1;
                            })) {
                            // We didn't find any arrays that had any
                            // variance so we want this as well.
                            commonalities[key] = values[0];
                        }
                    } else {
                        var uniqueValues = _.uniq(values);

                        if (uniqueValues.length == 1) {
                            commonalities[key] = uniqueValues[0];
                        }
                    }
                }
            }
        );

        return commonalities;
    } else {
        return { };
    }
}

console.log("commonalities: ", findCommonalities(model));

Performance seems fine with a small number of keys and a small number of items, but you'd need to test it with a million records and a large number of keys.

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