使用 lodash 而不是 for 循环

use lodash instead of forloop

我是 lodash 的新手,我想将这个使用 i 和 j 的 forloop 转换为 lodash,这样我的编码就减少了。

 for(var i =0 ; i < students.length; i++){
                for(var j = 0; j <marks.lab.length;j++){
                    if(students[i].sID === marks.lab[j].sID){
                        students[i].coding = data.lab[j].coding;
                    }
                }
            }

如果使用 lodash 还有其他优势,请告诉我。

从概念上讲,您正在尝试根据学生的 ID 在两个数据集之间进行连接。我不认为 lodash 有一个 sql-esque 连接,所以在没有它的情况下你可以像下面那样做简单的 O(n^2) 实现。

    var new_students = _.map(students, function(stud){
        var matching_score = _.chain(marks).filter(function(mark){
            return stud.sID == mark.lab.sID;
        })
        .first()
        .value();
        var new_student = _.cloneDeep(stud);
        new_student.coding = matching_score.coding;
        return new_student;
    });

请注意此 returns new 学生对象并且不会改变您的旧对象。也就是说,如果您关心性能并且不介意可变性,那么进行哈希连接将使您获得 O(n) 性能。

var sqljoin = function(first, second, first_on, second_on, item_maker){
    var first_dict = {};
    _.each(first, function(f){
        var key = first_on(f);
        if(! (key in first_dict) ){
            first_dict[key] = f;
        }
    });
    return _.chain(second).filter(function(s){
        var key = second_on(s);
        return key in first_dict;
    })
    .map(function(s){
        var key = second_on(s);
        var first_val = first_dict[key];
        var second_val = s;
        return item_maker(first_val, second_val);
    })
    .value();
};
_.mixin('sqljoin', sqljoin);

您可以通过 sID 使用 keyBy() to serve as reference. Use map to return a new array of students wherein it uses pick to get the keys that you want from the marks.lab cache, and then use assign() 添加所有学生属性来缓存 marks.lab 数组。这样做可以确保 students 数组不会发生变异。

var labs = _.keyBy(marks.lab, 'sID'); // cache by key
var result = _.map(students, function(student) {
  return _(labs[student.sID]) // get the cache
    .pick(['coding']) // This returns a new object
    .assign(student); // Assigns the student object
});

var students = [
  { sID: '1', name: 'Ryan' },
  { sID: '2', name: 'Rez James' },
  { sID: '3', name: 'Hazel Charmagne' }
];

var marks = {
  lab: [
    { sID: '1', coding: 'A' },
    { sID: '2', coding: 'A' },
    { sID: '3', coding: 'A' }
  ]
};

var labs = _.keyBy(marks.lab, 'sID'); // cache by key
var result = _.map(students, function(student) {
  return _(labs[student.sID]) // get the cache
    .pick(['coding']) // This returns an immutable object
    .assign(student); // Assigns the student object
});

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.js"></script>

更新

对于 lodash 3 的解决方案,您可以简单地更改 lodash 4 的 keyBy() with lodash 3's indexBy().

var labs = _.indexBy(marks.lab, 'sID'); // cache by key
var result = _.map(students, function(student) {
  return _(labs[student.sID]) // get the cache
    .pick(['coding']) // This returns an immutable object
    .assign(student); // Assigns the student object
});

var students = [
  { sID: '1', name: 'Ryan' },
  { sID: '2', name: 'Rez James' },
  { sID: '3', name: 'Hazel Charmagne' }
];

var marks = {
  lab: [
    { sID: '1', coding: 'A' },
    { sID: '2', coding: 'A' },
    { sID: '3', coding: 'A' }
  ]
};

var labs = _.indexBy(marks.lab, 'sID'); // cache by key
var result = _.map(students, function(student) {
  return _(labs[student.sID]) // get the cache
    .pick(['coding']) // This returns an immutable object
    .assign(student); // Assigns the student object
});

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdn.jsdelivr.net/lodash/3.10.1/lodash.js"></script>


使用lodash的优势是它提供了一些已经预先编写好的实用方法,可以节省资源和开发人员创建函数的时间。至于你的 for 循环解决方案的情况,你可能会说在更简单的情况下,一个简单的 for 循环比使用 lodash 实用方法更好和可读。

如果我们谈论性能,您可能会说在解决方案方面,您的 for 循环可能会影响性能,因为它是 O(N^2 ).您可能会创建一个 for 循环版本来缓存 marks.lab 数组,然后再次循环 students 数组以获得正确的输出:

var labs = {};
var i;

for(i = 0; i < marks.lab.length; i++) {
  labs[marks.lab[i].sID] = marks.lab.coding;
}

for(i = 0; i < students.length; i++) {
  students[i].coding = labs[students[i].sID];
}

上面的解决方案对于两个循环都有一个 O(N)。除了您的 for 循环解决方案和上面的 for 循环解决方案改变原始 students 数组的部分外,它更接近我上面提供的解决方案。当您想重用原始数组 可以 是一件坏事。让我们调整上面的 for 循环解决方案,以防止改变原始数组:

var labs = {};
var result = [];
var i;

for(i = 0; i < marks.lab.length; i++) {
  labs[marks.lab[i].sID] = marks.lab.coding;
}

for(i = 0; i < students.length; i++) {
  result.push(Object.assign(
    { coding: labs[students[i].sID] },
    students[i]
  ));
}

如果您将上面的 for 循环解决方案与我提供的 lodash 解决方案进行比较,那么它肯定会为您节省几行代码和编写代码的时间。