2014-10-15 26 views
5

Im sử dụng Node.js. (... và underscore.js)Kết hợp các mảng với các giá trị chồng chéo

Xem xét cấu trúc dữ liệu này

var numbers = [ 
    [10, 20] 
    [30, 40] 
    [40, 50] 
    [45, 70] 
    ... //Possibly more arrays (always contains two numbers) 
] 

numbers chứa mảng đó luôn chứa các cặp số. Hãy nghĩ về các cặp số này là "bắt đầu" và "kết thúc". Tôi muốn một hàm lấy numbers làm đối số và vòng lặp máng nội dung của nó và nếu số "bắt đầu" của một cặp chồng lên số "cuối" của cặp trước đó, các mảng này được hợp nhất thành một. Ví dụ này:

var numbers = [ 
    [10, 20] 
    [19, 40] 
    [40, 60] 
    [70, 80] 
] 

trở thành này:

var numbers = [ 
    [10, 60] // First, second and third array is merged because of overlapping . 
    [70, 80] 
] 

Thực ra, tôi đã có viết một chức năng cho điều này mà hoạt động tốt, nhưng cảm thấy một chút thời gian.

Tôi rất tò mò nếu một số thuật sĩ javascript có thể làm mê hoặc tôi bằng giải pháp siêu thanh lịch =).

+2

Thay vào đó, bạn có thể hiển thị cách triển khai của riêng mình và sau đó chúng tôi có thể chỉ cho bạn cách cải thiện. Trong trường hợp này, [Code Review] (http://codereview.stackexchange.com/) sẽ là một nơi tốt hơn để đăng bài này. – Brett

+0

Aah ... Tôi không biết về Code Review. Cảm ơn đã nói với tôi! –

+0

Về đăng giải pháp của riêng tôi ... Trên thực tế, những gì tôi muốn - như một lập trình viên khá tươi - là bằng chứng cho thấy nó ok để giải quyết vấn đề mã trong nhiều cách khác nhau. Nhiều lần tôi thấy mình suy nghĩ về giải pháp ABSOLUTE, mặc dù tôi bằng cách nào đó cũng tin rằng có vô số cách mà đều tốt như nhau. Bằng cách không đăng giải pháp của riêng tôi, tôi có thể được trình bày cho một số giải pháp tốt khác nhau không thiên vị của riêng tôi. –

Trả lời

4

Tạo một trống rỗng "kết quả " mảng. Lặp qua mảng phạm vi và thay đổi mục cuối cùng của kết quả hoặc thêm phạm vi hiện tại vào đó.

function merge(ranges) { 
 
    var result = [], last; 
 

 
    ranges.forEach(function (r) { 
 
     if (!last || r[0] > last[1]) 
 
      result.push(last = r); 
 
     else if (r[1] > last[1]) 
 
      last[1] = r[1]; 
 
    }); 
 

 
    return result; 
 
} 
 

 
r = [[10, 20], [19, 40], [40, 60], [70, 80]]; 
 
document.write(JSON.stringify(merge(r)));

này giả định rằng các mảng nguồn được sắp xếp, nếu nó không phải luôn luôn như vậy, sắp xếp nó trước khi sáp nhập:

ranges.sort(function(a, b) { return a[0]-b[0] || a[1]-b[1] }); 
+0

Giải pháp này rất giống với giải pháp của riêng tôi. Sự khác biệt duy nhất là bạn đã xoay xở để giảm hai 'nếu chỉ có một người. Tôi đã có một bên ngoài 'if' để kiểm tra'! Result.length'. Linh hồn của bạn đã giúp tôi tiết kiệm bốn hàng và một số thụt đầu dòng = D. –

+0

giải pháp của bạn không hoạt động. thử: [10,20], [11,12], [25,30] – YardenST

+0

@YardenST: cảm ơn, đã sửa! – georg

5

Tôi tạo ra một chức năng mà làm những gì bạn muốn:

function merge(arr) { 
    // copy and sort the array 
    var result = arr.slice().sort(function(a, b) { 
      return a[0] > b[0]; 
     }), 
     i = 0; 

    while(i < result.length - 1) { 
     var current = result[i], 
      next = result[i+1]; 

     // check if there is an overlapping 
     if(current[1] >= next[0]) { 
      current[1] = Math.max(current[1], next[1]); 
      // remove next 
      result.splice(i+1, 1); 
     } else { 
      // move to next 
      i++; 
     } 
    } 
    return result; 
}; 

Chức năng này có thể được sử dụng theo cách này:

var mergedNumbers = merge(numbers); 


DEMO

+0

Đây là rất tốt, bởi vì nó hoạt động mà không foreach và không giảm, vì vậy tôi có thể sử dụng nó trong ExtendScript. Cảm ơn! +1 – mdomino

1

Như @Brett nói, đây có thể là một phù hợp hơn cho Code Review (chỉ cần chắc chắn bao gồm việc triển khai hiện tại của bạn). Nếu bạn đăng ở đó, đặt một tham chiếu đến nó ở đâu đó và tôi sẽ di chuyển câu trả lời của tôi.


Giả sử rằng mảng numbers của bạn đã được sắp xếp một cách chính xác, chức năng này nên làm những gì bạn muốn:

function combine(numbers) { 
 
    return numbers.reduce(function(combined, next) { 
 
     if (!combined.length || combined[combined.length-1][1] < next[0]) combined.push(next); 
 
     else { 
 
      var prev = combined.pop(); 
 
      combined.push([prev[0], Math.max(prev[1], next[1])]); 
 
     } 
 
    \t return combined; 
 
    }, []); 
 
} \t \t 
 

 
var n = [[10, 20], [19, 40], [40, 60], [70, 80], [75, 76]]; 
 
var r = combine(n); 
 
document.write('<pre>' + JSON.stringify(r) + '</pre>');

này "reduce s" mảng ban đầu cho cái mới sử dụng logic sau trong hàm reduce:

  1. Nếu đây là lần đầu tiên vượt qua hoặc mục cuối cùng không chồng chéo mục hiện tại, push mục hiện tại vào mảng combined.
  2. Nếu không:
    1. pop mục cuối cùng khỏi mảng combined.
    2. push sự kết hợp của mục cuối cùng và mục hiện hành về đến các mảng combined.
Các vấn đề liên quan