getChangeSet

liyinkan發表於2014-01-09

有時候我們需要區分一堆 List 的 changeset。特別是當這個 List 可以被增加可以被修改可以被刪除的時候。
需要獲得以下幾個 List

  • added_list
  • updated_list
  • deleted_list
  • unchanged_list

寫了一個 JS 實現。
入參是四個 original, current, getKeyFunction, checkUpdatedFunction
前兩個沒什麼好說了。

  • getKeyFunction 預設是返回入參本身。如果入參 List 是 Object 可以返回這個 Object 的 Oid 之類的值。
  • checkUpdatedFunction 是比對是否有修改過的方法。預設比對兩個 Object 的 JSON 值。

磚頭還是輕輕的來比較好 ……

function getChangeSet(original, current, getKeyFunction, checkUpdatedFunction) {
    original = [].concat(original);
    current = [].concat(current);
    if (getKeyFunction == undefined) {
        getKeyFunction = function(item) {
            return item;
        }
    }
    if (checkUpdatedFunction == undefined) {
        checkUpdatedFunction = function(obj1, obj2) {
            return JSON.stringify(obj1) != JSON.stringify(obj2);
        }
    }
    var listToMap = function(list) {
        var ret = {};
        for (var i = 0, l = list.length; i < l; i++) {
            ret[getKeyFunction(list[i])] = list[i];
        }
        return ret;
    };
    var getValueListOfMap = function(map) {
        var ret = [];
        for (var key in map) {
            if (map.hasOwnProperty(key)) {
                ret.push(map[key]);
            }
        }
        return ret;
    };
    var getKeyListOfMap = function(map) {
        var ret = [];
        for (var key in map) {
            if (map.hasOwnProperty(key)) {
                ret.push(key);
            }
        }
        return ret;
    };
    var weightMap = {},
        calWeight = function(list, weight, weightMap) {
            for (var i = 0, l = list.length; i < l; i++) {
                var key = list[i];
                if (typeof weightMap[key] === "number") {
                    weightMap[key] += weight;
                } else {
                    weightMap[key] = weight;
                }
            }
        }
    var added = [],
        updated = [],
        deleted = [],
        unchanged = [];
    var oriMap = listToMap(original),
        curMap = listToMap(current),
        oriKeys = getKeyListOfMap(oriMap),
        curKeys = getKeyListOfMap(curMap);
    calWeight(oriKeys, 1, weightMap);
    calWeight(curKeys, 2, weightMap);
    for (var key in weightMap) {
        if (weightMap.hasOwnProperty(key)) {
            var value = weightMap[key];
            if (value == 3) {
                if (checkUpdatedFunction(oriMap[key], curMap[key])) {
                    updated.push(curMap[key]);
                } else {
                    unchanged.push(oriMap[key]);
                }
            } else if (value == 2) {
                added.push(curMap[key]);
            } else if (value == 1) {
                deleted.push(oriMap[key]);
            }
        }
    }
    return {
        added: added,
        updated: updated,
        deleted: deleted,
        unchanged: unchanged
    };
}

以下 tests 通過了

test1 = function() {
    var ori = ['t1', 't2'];
    var cur = ['t1', 't3'];
    return getChangeSet(ori, cur)
}
test2 = function() {
    var ori = [{
        key: 't1',
        value: 'v1'
    }, {
        key: 't2',
        value: 'v2'
    }, {
        key: 't4',
        value: 'v4'
    }];
    var cur = [{
        key: 't1',
        value: 'vx'
    }, {
        key: 't3',
        value: 'v3'
    }, {
        key: 't4',
        value: 'v4'
    }];
    return getChangeSet(ori, cur,
        function(item) {
            return item.key;
        })
}