2011-11-29 51 views
12

dữ liệu gốc JSON (phẳng bảng):Chuyển đổi mảng phẳng của đối tượng vào mảng lồng nhau của các đối tượng

[ 
    {"id":"1","first_name":"Jason","last_name":"Martin","start_date":"1996-07-25","end_date":"2006-07-25","salary":"1234.56","city":"Toronto","description":"Programmer","department":"Finance","active":"1"}, 
    {"id":"2","first_name":"Alison","last_name":"Mathews","start_date":"1976-03-21","end_date":"1986-02-21","salary":"6661.78","city":"Vancouver","description":"Tester","department":"Finance","active":"1"}, 
    {"id":"3","first_name":"James","last_name":"Smith","start_date":"1978-12-12","end_date":"1990-03-15","salary":"6544.78","city":"Vancouver","description":"Tester","department":"QA","active":"1"}, 
    {"id":"4","first_name":"Celia","last_name":"Rice","start_date":"1982-10-24","end_date":"1999-04-21","salary":"2344.78","city":"Vancouver","description":"Manager","department":"HR","active":"1"}, 
    {"id":"5","first_name":"Robert","last_name":"Black","start_date":"1984-01-15","end_date":"1998-08-08","salary":"2334.78","city":"Vancouver","description":"Tester","department":"IT","active":"1"}, 
    {"id":"6","first_name":"Linda","last_name":"Green","start_date":"1987-07-30","end_date":"1996-01-04","salary":"4322.78","city":"New York","description":"Tester","department":"QA","active":"1"}, 
    {"id":"7","first_name":"David","last_name":"Larry","start_date":"1990-12-31","end_date":"1998-02-12","salary":"7897.78","city":"New York","description":"Manager","department":"HR","active":"1"} 
] 

tôi cần phải gọi hàm như thế này:

nest(data,["city","description","department"]) 

Tham số đầu tiên là toàn bộ tập dữ liệu, thứ hai là một mảng các cột xác định cấp độ lồng nhau.

mong đợi đầu ra JSON:

[ 
{key: "city", value: "Toronto", count: 1, children: 
    [ 
     {key: "description", value: "Programmer", count: 1, children: 
      [ 
       {key: "department", value: "Finance", count: 1} 
      ] 
     } 
    ] 
}, 
{key: "city", value: "Vancouver", count: 2, children: 
    [ 
     {key: "description", value: "Tester", count: 3, children: 
      [ 
       {key: "department", value: "Finance", count: 1}, 
       {key: "department", value: "QA", count: 1}, 
       {key: "department", value: "IT", count: 1} 
      ] 
     }, 
     {key: "description", value: "Manager", count: 1} 
    ] 
}, 

{key: "city", value: "New York", count: 2, children: 
    [ 
     {key: "description", value: "Tester", count: 1, children: 
      [ 
       {key: "department", value: "QA", count: 1} 
      ] 
     }, 
     {key: "description", value: "Manager", count: 1, children: 
      [ 
       {key: "department", value: "HR", count: 1} 
      ] 
     } 
    ] 
} 

]

Tôi đã thử viết một vài chức năng đệ quy nhưng cứ bị mắc kẹt khi tôi phải tự động tìm kiếm trên cây để tránh trùng lặp.

+1

Tại sao '{key:" department ", value:" Tài chính", count: 1} 'thay vì' {key: "department", value: "Finance", count: 0} '? Nút đó không có con. –

+0

Chào mừng bạn đến với [SO]; vui lòng đọc [faq]. – zzzzBov

+0

Số đếm là gì? Nó là 1 ngay cả khi trẻ em bằng không? – goat

Trả lời

9

Nghĩ rằng đây là một câu hỏi thú vị, vì vậy tôi đã làm ... nhưng, tôi đồng ý với những người đã hỏi "bạn đã thử gì cho đến nay". Thông thường, bạn nên nói về một sự cố cụ thể.

// Groups a flat array into a tree. 
// "data" is the flat array. 
// "keys" is an array of properties to group on. 
function groupBy(data, keys) { 

    if (keys.length == 0) return data; 

    // The current key to perform the grouping on: 
    var key = keys[0]; 

    // Loop through the data and construct buckets for 
    // all of the unique keys: 
    var groups = {}; 
    for (var i = 0; i < data.length; i++) 
    { 
     var row = data[i]; 
     var groupValue = row[key]; 

     if (groups[groupValue] == undefined) 
     { 
      groups[groupValue] = new Array(); 
     } 

     groups[groupValue].push(row); 
    } 

    // Remove the first element from the groups array: 
    keys.reverse(); 
    keys.pop() 
    keys.reverse(); 

    // If there are no more keys left, we're done: 
    if (keys.length == 0) return groups; 

    // Otherwise, handle further groupings: 
    for (var group in groups) 
    { 
     groups[group] = groupBy(groups[group], keys.slice()); 
    } 

    return groups; 
} 

Gọi phương pháp như thế này:

var groupedData = groupBy(data, ["city","description","department"]); 

Kết quả của phương pháp này cho dữ liệu của bạn trông như thế này:

{ 
    "Toronto": { 
     "Programmer": { 
      "Finance": [ 
       { 
        "id": "1", "first_name": "Jason", "last_name": "Martin", "start_date": "1996-07-25", "end_date": "2006-07-25", "salary": "1234.56", "city": "Toronto", "description": "Programmer", "department": "Finance", "active": "1" 
       } 
      ] 
     } 
    }, 
    "Vancouver": { 
     "Tester": { 
      "Finance": [ 
       { 
        "id": "2", "first_name": "Alison", "last_name": "Mathews", "start_date": "1976-03-21", "end_date": "1986-02-21", "salary": "6661.78", "city": "Vancouver", "description": "Tester", "department": "Finance", "active": "1" 
       } 
      ], 
      "QA": [ 
       { 
        "id": "3", "first_name": "James", "last_name": "Smith", "start_date": "1978-12-12", "end_date": "1990-03-15", "salary": "6544.78", "city": "Vancouver", "description": "Tester", "department": "QA", "active": "1" 
       } 
      ], 
      "IT": [ 
       { 
        "id": "5", "first_name": "Robert", "last_name": "Black", "start_date": "1984-01-15", "end_date": "1998-08-08", "salary": "2334.78", "city": "Vancouver", "description": "Tester", "department": "IT", "active": "1" 
       } 
      ] 
     }, 
     "Manager": { 
      "HR": [ 
       { 
        "id": "4", "first_name": "Celia", "last_name": "Rice", "start_date": "1982-10-24", "end_date": "1999-04-21", "salary": "2344.78", "city": "Vancouver", "description": "Manager", "department": "HR", "active": "1" 
       } 
      ] 
     } 
    }, 
    "New York": { 
     "Tester": { 
      "QA": [ 
       { 
        "id": "6", "first_name": "Linda", "last_name": "Green", "start_date": "1987-07-30", "end_date": "1996-01-04", "salary": "4322.78", "city": "New York", "description": "Tester", "department": "QA", "active": "1" 
       } 
      ] 
     }, 
     "Manager": { 
      "HR": [ 
       { 
        "id": "7", "first_name": "David", "last_name": "Larry", "start_date": "1990-12-31", "end_date": "1998-02-12", "salary": "7897.78", "city": "New York", "description": "Manager", "department": "HR", "active": "1" 
       } 
      ] 
     } 
    } 
} 

Bởi vì các nhóm đều đối tượng javascript, bạn don' t cần thành viên "đếm" đó. Bạn chỉ có thể sử dụng thuộc tính .length của (các) mảng.

Lặp lại các nhóm bằng cách sử dụng cú pháp for (var group in groups) của javascript.

+1

Điều đó thực sự hữu ích, cảm ơn bạn. – WeaponX86

+0

Một giải pháp tốt đẹp, tiết kiệm cho sau này. –

7

Bạn có thể có một cái nhìn tại nest() điều hành từ D3.js: https://github.com/mbostock/d3/blob/48ad44fdeef32b518c6271bb99a9aed376c1a1d6/src/arrays/nest.js Đây là một phần của D3, một thư viện lớn, nhưng nhìn một cách nhanh chóng vào mã tôi chỉ liên quan đến, tôi không nghĩ rằng đây có bất kỳ phụ thuộc, vì vậy bạn sẽ có thể nâng mã ở đây để sử dụng trong dự án của riêng bạn. Cách sử dụng là described here in the docs - bạn chuỗi .key() các phương pháp để xác định các khóa cho mỗi lớp của cấu trúc lồng nhau. Trong trường hợp của bạn, điều này có thể trông giống như:

data = d3.nest() 
    .key(function(d) { return d.city }) 
    .key(function(d) { return d.description }) 
    .entries(data); 

Cấu trúc này sẽ thét ra là một chút khác biệt so với những gì bạn có, nhưng đó là chức năng khá tương tự:

[ 
    { 
    "key": "Toronto", 
    "values": [ 
     { 
     "key": "Programmer", 
     "values": [ 
      { 
      "active": "1", 
      "city": "Toronto", 
      "department": "Finance", 
      "description": "Programmer", 
      "end_date": "2006-07-25", 
      "first_name": "Jason", 
      "id": "1", 
      "last_name": "Martin", 
      "salary": "1234.56", 
      "start_date": "1996-07-25" 
      }, 
      // etc ... 
     ] 
     } 
    ] 
    }, 
    // etc ... 
] 
+0

+1 Tốt nhất ... có một vài lợi ích so với phiên bản nhanh chóng và bẩn mà tôi đặt cùng nhau, bao gồm; các khóa có thể lựa chọn của nhà phát triển (có nghĩa là sẽ dễ dàng làm cho các khóa không phân biệt chữ hoa chữ thường hoặc được tính toán) và sắp xếp. Cá nhân, tôi có lẽ sẽ tinh chỉnh phiên bản của tôi để thêm những tính năng thay vì brining trong (khác) thư viện ... nhưng tốt đẹp tìm thấy! – Steve

+1

Cảm ơn - bạn không cần toàn bộ thư viện, chỉ là hàm trong mã tôi liên kết đến, không có bất kỳ phụ thuộc D3 nào. Nhưng đúng là nó có thể là quá mức cần thiết đối với một số dự án. – nrabinowitz

+0

Tôi chắc chắn sẽ xem xét điều này, tìm kiếm tốt đẹp! – WeaponX86

0

Dựa trên ví dụ được cung cấp bởi @ nrabinowitz, đây là hàm lồng với API được đề xuất ban đầu để chuyển bộ sưu tập và một mảng tên thuộc tính như args, sử dụng d3.nest dưới mui xe:

function nest(data, keys) { 
    var nest = d3.nest(); 
    keys.forEach(function(k) { 
    nest.key(function(d) { 
     return d[k]; 
    }) 
    }); 
    return nest.entries(data); 
} 
Các vấn đề liên quan