2017-01-24 18 views
6

Tôi thường cần để ánh xạ một danh sách các hàm (xử lý) với một số mảng (kênh) của dữ liệu float) vì vậy tôi đã viết một hàm helper ...Lập bản đồ một loạt các chức năng trên một mảng trong Javascript

const mapMany = function(processors, channels){ 
    processors.forEach(function(processor){ 
    channels = channels.map((channel) => channel.map(processor)); 
    }); 
    return channels; 
}; 

Điều này đọc OK (với tôi ít nhất!) Nhưng ánh xạ một mảng các hàm trên một mảng khác có vẻ giống như một điều chung chung mà tôi không thể không tự hỏi nếu nó là "một điều" đã có nghĩa là có tốt hơn/được xây dựng trong/cách kinh điển để thực hiện chức năng kiểu "Bản đồ nhiều" này và nếu vậy thì tên thích hợp cho nó là gì?

Trả lời

5

Có, có cách tiếp cận tốt hơn để thực hiện việc này. Không sử dụng forEach!

function mapMany(processors, channels) { 
    return processors.reduce((channels, processor) => 
     channels.map(channel => channel.map(processor)) 
    , channels); 
} 

Nhưng không, không có nội dung này cũng không phải là tên chuẩn cho nó. Đó là một chức năng khá cụ thể, tuy nhiên nó có thể được tạo thành từ các khối xây dựng tiêu chuẩn.

+0

Cảm ơn. Tôi nghĩ rằng tôi đã thử điều đó nhưng hóa ra tôi đã vượt qua việc giảm các thông số của nó một cách sai lầm! – technicalbloke

1

Vì vậy, khi Bergi chỉ ra nó đã được chỉ đơn giản là giảm tôi đang tìm kiếm, chia tách nó thành hai chức năng làm cho nó rõ ràng hơn nhiều ...

const applySingleProcessor = function(channels, processor){ 
    return channels.map(channel => channel.map(processor)); 
}; 

const applyMultipleProcessors = function(processors, channels) { 
    return processors.reduce(applySingleProcessor, channels); 
}; 

Yay đơn giản!

4

Tôi nghĩ bạn đang tìm kiếm compose. Nó trông giống như sau:

const compose = function (...fns) { 
    const rest = fns.reverse(); 
    const first = rest.shift(); 
    return function (...args) { 
     return rest.reduce((acc, f)=>f.call(this, acc), first.apply(this, args)); 
    }; 
}; 

Bây giờ bạn có thể soạn các chức năng như thế này:

const stringDouble = compose(String, x=>x*2); 
stringDouble("44"); //==> "88" 

["22","33","44"].map(stringDouble); 
//=> ["44", "66", "88"] 

Và trong trường hợp của bạn, bạn có thể viết chức năng của bạn như thế này:

const mapMany = function(processors, channels){ 
    // compose iterates from last to first so i apply reverse 
    const fun = compose.apply(undefined, processors.reverse()); 
    return channels.map(fun); 
}; 

Các lợi thế hơn mã của riêng bạn và câu trả lời khác bằng cách sử dụng reduce là điều này không làm cho các mảng processors.length trong quá trình này mà chỉ là một mảng.

Có thư viện cung cấp compose. Đó là một chức năng phổ biến trong lập trình hàm.

Các chức năng ánh xạ khác như các chức năng bản đồ trong Gạch dưới cho phép bạn đặt this. Sau đó, các phương thức lớp sẽ hoạt động khi tôi chuyển các hàm cơ bản cũng như this.

+0

'map (f). map (g) = map (f. g) 'là một định danh hữu dụng _and_. – phg

+0

Cảm ơn. Điều đó có vẻ đáng yêu. Đến từ nhiều thập kỷ mã hóa bắt buộc, nó có thể khiến tôi mất một thời gian để mò mẫm nó nhưng tôi sẽ nhìn chằm chằm vào nó cho đến khi tôi làm! – technicalbloke

+0

@technicalbloke Nó không phải là khó khăn. Về cơ bản, 'compose (a, b, c)' giống như '(... args) => a (b (c (... args)))' vì vậy nó chỉ tổng quát hơn. – Sylwester

0

Mặc dù tôi thường sử dụng .reduce() vì @Bergi đã làm, chỉ cho một loạt ở đây là một giải pháp đệ quy đơn giản .map() mà không cần .reduce();

var channels = [[1,2,3,4],[5,6,7,8], [857,1453,1881,1071]], 
 
    processors = [x => x+1, x => x*x, x => Math.sqrt(x), x => x-1], 
 
    mapMany = (processors, channels) => processors.length ? (channels = channels.map(c => c.map(processors[0])), 
 
                   mapMany(processors.slice(1),channels)) 
 
                  : channels; 
 
console.log(mapMany(processors,channels));

Các vấn đề liên quan