2012-03-16 21 views
16

Có thể kết hợp bộ lọc và bản đồ của Underscore không? Tôi hiện đang có hai cuộc gọi chức năng riêng biệt, nhưng tôi tự hỏi nếu tôi có thể làm cho chúng hiệu quả hơn bằng cách kết hợp chúng thành một cuộc gọi duy nhất, bằng cách nào đó.Làm thế nào để đạt được hiệu quả tối đa với bản đồ và bộ lọc của gạch dưới?

Về cơ bản tôi có một dãy tên quốc gia - tôi muốn lọc chúng bằng cách sử dụng regex, sau đó ánh xạ kết quả đã lọc vào một mảng đối tượng DataItem. Đây là mã hiện tại của tôi:

var filteredData = _.filter(allCountries, function(n, i){ 
    var re = RegExp("^" + searchString, "i"); 
    if (re.exec(n['country'].toLowerCase()) !== null) { 
    return true; 
    } 
}); 
var mappedData = _.map(filteredData, function(n, i){ 
    return new DataItem(i, n['name'], n['budget']); 
}); 

Bất kỳ mẹo nào khác để cải thiện hiệu quả cũng sẽ được biết ơn.

Trả lời

11

Bạn có thể sử dụng thay vì each:

result = [] 
_.each(array, function(elem) { 
    if(elem.indexOf(search) == 0) 
     result.push(...whatever...) 

Cũng lưu ý rằng bạn không cần một biểu hiện thường xuyên chỉ để tìm hiểu xem một chuỗi bắt đầu với một số khác.

+2

Chuỗi được ưu tiên hơn cho mỗi –

+0

@itcouldevenbeaboat: có thể, tôi không sử dụng gạch dưới nhiều ... Trong trường hợp cụ thể này, mỗi chữ có vẻ dễ đọc hơn. – georg

+0

Điều này không tốt bởi vì bây giờ bạn đã giới thiệu biến 'result' có thể thay đổi không cần thiết. Người ta có thể cho rằng bạn cũng có thể sử dụng vòng lặp 'for' trong trường hợp này. 'chuỗi' là cách ưa thích để đi. – spinningarrow

33

gạch cung cấp một khả năng chaining qua _.chain:

_.chain(allCountries) 
.filter(function(n, i) { ... }) 
.map(function(n, i) { ... }) 
.value(); // stop chaining and get the result 

Thay vì re.exec(...) !== null bạn có thể sử dụng re.test(...), và lưu ý rằng bạn cần phải thoát khỏi nhân vật regexp đặc biệt cho searchString.

Trong trường hợp đơn giản này tuy nhiên, nó tốt hơn để sử dụng .indexOf để kiểm tra xem chuỗi bắt đầu với một chuỗi con:

// substring should be apparent at position 0, discard case for both strings 
return n.country.toLowerCase().indexOf(searchString.toLowerCase()) === 0; 

Đối với xâu, .foo có thể rõ ràng hơn so với ['foo'].

+0

Đây chắc chắn là câu trả lời! – nick4fake

8

Câu trả lời của pimvdb là cách chúng tôi làm những việc trong lập trình hàm/underscore.js đó là một chút tối ưu hóa sớm để thực hiện cả hai bước cùng một lúc. JS không được hưởng lợi nhiều từ việc thực hiện những điều này một cách riêng biệt.

_.chain(allCountries) 
.filter(function(n, i) { ... }) 
.map(function(n, i) { ... }) 
.value(); 

ở trên rất dễ hiểu, nhưng khi chúng tôi bắt đầu kết hợp các trách nhiệm thì mọi thứ sẽ trở nên dễ dàng.

_.mapFilter (mảng, filterFn, mapFn) ...

với chaining chúng ta phải hy sinh hiệu suất cho năng suất. Cả hai đều quan trọng, nhưng luôn luôn quan trọng hơn cái kia. Chúng tôi không thể quay lại và cải thiện năng suất, nhưng chúng tôi có thể cải thiện hiệu suất sau khi thực tế.

+0

Điều này xứng đáng được thăng hạng nhiều hơn! "Chúng tôi không thể quay trở lại và cải thiện năng suất, nhưng chúng tôi có thể cải thiện hiệu suất sau khi thực tế." Khái niệm tuyệt vời! –

11

Sử dụng _.reduce vì nó tiết kiệm n lần lặp. Kéo RegEx của bạn ra khỏi vòng lặp để bạn không tạo lại đối tượng mỗi lần lặp. Sử dụng test thay vì exec (nhanh hơn vì đó là kết quả boolean đơn giản).

var re = RegExp("^" + searchString, "i"); 
var data = _.reduce(allCountries, function(res, n, i) { 
    if (re.test(n['country'])) { 
    res.push(new DataItem(i, n['name'], n['budget'])); 
    } 
    return res; 
}, []); 
Các vấn đề liên quan