2013-11-27 15 views
5

Tôi có một đối tượng phẳng và một mảng mà từ đó tôi cần phải xây dựng một đối tượng giống cây.Làm thế nào để lặp qua Object và tạo một đối tượng cây

choices: ['choice1', 'choice2', 'choice3']; 
items: [ 
    { 
     choice1: 'taste', 
     choice2: 'good', 
     choice3: 'green-lemon' 
    }, 
    { 
     choice1: 'taste', 
     choice2: 'bad', 
     choice3: 'green-lemon' 
    } 
]; 

Mảng mô tả mức mà mỗi sự lựa chọn sẽ đến trên cây. Tôi không biết có bao nhiêu sự lựa chọn, vật phẩm hoặc cấp độ sẽ có sau này.

Làm thế nào để có được các đối tượng sau đây:

output: { 
    taste: { 
     good: { 
      green-lemon:1 
     }, 
     bad: { 
      green-lemon:1 
     } 
    } 
} 

tôi cần để có được một đối tượng mô tả cách nhiều mặt hàng có trên mỗi cấp. Trong ví dụ này, đây là choice1: 1;choice2: 2 và mỗi choice3: 1.

Bất kỳ lời khuyên nào về cách tạo vòng lặp để nhận kết quả này?

+0

Có sẽ là mức hơn điều này? Bộ dữ liệu này có bao giờ mở rộng không? –

+0

Mảng 'choice' có nghĩa là để mô tả mức độ mà mỗi sự lựa chọn đến trong cây? @ brainwipe của câu hỏi cũng có liên quan đến một giải pháp đúng. –

+0

@brainwipe: Có thể chỉ có 2 cấp độ lựa chọn và có thể có 5 cấp độ lựa chọn. Mảng lựa chọn và đối tượng items sẽ không bao giờ thay đổi trong suốt thời gian chạy. – Dinkheller

Trả lời

2

Tôi nghĩ giải pháp tốt nhất ở đây là vòng lặp với một số đệ quy. Tôi đã tăng kích thước của mô hình trong ví dụ để cho thấy nó đi với n cấp độ. Kiểm tra đầu ra bằng bảng điều khiển javascript của bạn.

var choices = ['choice1', 'choice2', 'choice3']; 
var items = [{ 
    choice1: 'taste', 
    choice2: 'good', 
    choice3: 'green-lemon' 
}, { 
    choice1: 'taste', 
    choice2: 'bad', 
    choice3: 'green-lemon' 
}, 
{ 
    choice1: 'taste', 
    choice2: 'ok', 
    choice3: 'green-lemon' 
}, 
{ 
    choice1: 'taste', 
    choice2: 'ok', 
    choice3: 'green-lemon' 
}]; 

function IsLastLevel(levelIndex) { 
    return (levelIndex == choices.length - 1); 
} 

function HandleLevel(currentItem, currentLevel, nextChoiceIndex) { 

    var nextLevelName = currentItem[choices[nextChoiceIndex]]; 

    if (typeof currentLevel[nextLevelName] === 'undefined') { 
     currentLevel[nextLevelName] = {}; 
    } 

    if (IsLastLevel(nextChoiceIndex)) { 
     if (currentLevel[nextLevelName] > 0) { 
      currentLevel[nextLevelName]++; 
     } else { 
      currentLevel[nextLevelName] = 1; 
     } 
    } else { 
     var goOneDeeper = nextChoiceIndex + 1; 
     HandleLevel(currentItem, currentLevel[nextLevelName], goOneDeeper); 
    } 
} 

var output = {}; 

for(var itemIndex in items) 
{ 
    var item = items[itemIndex]; 
    HandleLevel(item, output, 0); 
} 

console.log(output); 

JsFiddle Demo

+0

tuyệt vời. Cảm ơn rất nhiều. – Dinkheller

0

Bạn có thể làm rõ mối quan hệ của dữ liệu này không?

nơi nào giá trị của '1' đến từ đây: "xanh-lemmon: 1"

mục đích của "lựa chọn" mảng là gì?

+0

'1' mô tả rằng chỉ có một mục có màu xanh chanh trong hương vị -> tốt. Và một trong hương vị -> xấu – Dinkheller

2

Brainwipe đã được đưa ra một câu trả lời rất sạch sẽ, nhưng tôi nghĩ rằng tôi sẽ cố gắng bàn tay của tôi anyway. Giải pháp này hoạt động bằng cách đệ quy giảm danh sách các mục, mức độ theo cấp độ, cho đến khi nó đạt đến các nút lá.

function choiceTree(items, choices) { 
    // Return empty object if there were no choices. 
    if (!choices.length) return {}; 

    var choice = choices.shift(); 

    // Construct the current level of the tree. 
    var level = items.reduce(function(node, item) { 
     var value = item[choice]; 

     // Add item if branch node or set to 1 if leaf node. 
     node[value] = (choices.length) 
      ? (node[value] || []).concat(item) 
      : 1; 

     return node; 
    }, {}); 

    // Return if there are no remaining choices. 
    if (!choices.length) return level; 

    // Recursively construct the next level. 
    for (var node in level) 
     level[node] = choiceTree(level[node], choices.slice()); 

    return level; 
} 

jsFiddle demo

+0

Cảm ơn rất nhiều. Đó là cách ít mã hơn, nhưng khó đọc hơn. Tôi đã không làm việc với giảm được nêu ra, nhưng chắc chắn sẽ xem xét nó. Cảm ơn. – Dinkheller

+2

'Array.reduce' thực sự tuyệt vời và không được sử dụng, bạn chắc chắn nên đọc nó! :) Tất cả nó làm là "giảm" một mảng thành một giá trị duy nhất; bạn có thể [sử dụng một 'for' loop thay vì] (http://jsfiddle.net/Jordan/j5aXL/), nhưng tôi nghĩ rằng mã phụ là messier. Nó không được hỗ trợ trong IE 8 trở xuống, nhưng nó [dễ dàng để shim] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Compatibility). –

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