Mảng liên kết đa chiều trong JavaScript


84

Có các kết quả truy vấn sau: (key1 và key2 có thể là bất kỳ văn bản nào)

id   key1     key2     value

1    fred     apple    2
2    mary     orange   10
3    fred     banana   7
4    fred     orange   4
5    sarah    melon    5
...

và tôi muốn lưu trữ dữ liệu trong một lưới (có thể là một mảng) lặp lại tất cả các bản ghi như thế này:

         apple    orange   banana  melon
fred        2        4         7     -
mary        -        10        -     -
sarah       -        -         -     5

Trong PHP, điều này sẽ thực sự dễ dàng, sử dụng các mảng kết hợp:

$result['fred']['apple'] = 2;

Nhưng trong các mảng liên kết JavaScript như thế này không hoạt động. Sau khi đọc rất nhiều hướng dẫn, tất cả những gì tôi có thể nhận được là:

arr=[];
arr[1]['apple'] = 2;

nhưng arr['fred']['apple'] = 2;không hoạt động. Tôi đã thử các mảng đối tượng, nhưng thuộc tính đối tượng không thể là văn bản tự do. Tôi càng đọc hướng dẫn, tôi càng bối rối ...

Mọi ý tưởng đều được hoan nghênh :)


Cảm ơn bạn đã trả lời, nhưng tôi đang lặp lại các kết quả truy vấn và tôi muốn đặt các giá trị lần lượt. Các dòng ví dụ (lấy ví dụ ở dạng Matt) var grid = {};grid['aa']['bb'] = 1;trả về "Uncaught TypeError: Cannot set property 'bb' of undefined". Tôi có thể sai, nhưng với hầu hết các ví dụ của bạn, tôi phải biết dữ liệu tại thời điểm khởi tạo.
Omiod

Chỉ cần tìm thấy rằng var grid = {}; grid['aa'] = {}; grid['aa']['bb'] = 1;hoạt động. Một thử nghiệm phức tạp hơn không, nhưng có vẻ như tôi đang ở trong con đường đúng đắn
Omiod

2
bạn phải khởi tạo đối tượng con trước, như tôi đã đề cập trong câu trả lời của mình. var lưới = {}; grd ['aa'] = {}; thì bạn có thể thực hiện lưới ['aa'] ['bb'] = 1. Có nhiều cách để kiểm tra xem đối tượng con đã được khởi tạo chưa (như đã đề cập trong câu trả lời của tôi), vì vậy bạn không ghi đè đối tượng hiện có vật.
Matt

đã cập nhật câu trả lời của tôi với một số mã bổ sung. không chắc chắn cách sâu đối tượng của bạn, hoặc làm thế nào bạn đang nhận được dữ liệu của bạn, nhưng hy vọng sẽ chỉ cho bạn đi đúng hướng
Matt

Câu trả lời:


152

Chỉ cần sử dụng một đối tượng JavaScript thông thường, đối tượng này sẽ 'đọc' theo cách giống như các mảng liên kết của bạn. Bạn cũng phải nhớ khởi tạo chúng trước.

var obj = {};

obj['fred'] = {};
if('fred' in obj ){ } // can check for the presence of 'fred'
if(obj.fred) { } // also checks for presence of 'fred'
if(obj['fred']) { } // also checks for presence of 'fred'

// The following statements would all work
obj['fred']['apples'] = 1;
obj.fred.apples = 1;
obj['fred'].apples = 1;

// or build or initialize the structure outright
var obj = { fred: { apples: 1, oranges: 2 }, alice: { lemons: 1 } };

Nếu bạn đang xem xét các giá trị, bạn có thể có một cái gì đó giống như sau:

var people = ['fred', 'alice'];
var fruit = ['apples', 'lemons'];

var grid = {};
for(var i = 0; i < people.length; i++){
    var name = people[i];
    if(name in grid == false){
        grid[name] = {}; // must initialize the sub-object, otherwise will get 'undefined' errors
    }

    for(var j = 0; j < fruit.length; j++){
        var fruitName = fruit[j];
        grid[name][fruitName] = 0;
    }
}

Được quản lý để sử dụng ví dụ trên mã sản xuất (một tiện ích mở rộng của Chrome) và hoạt động tốt. Cảm ơn. Cuối cùng, tôi đang tìm cách xử lý đối tượng trong JS!
Omiod

3
Không thể ủng hộ câu trả lời này đủ! Phần khiến đối tượng của tôi liên tục trả về không xác định là tôi KHÔNG khởi tạo đối tượng con. Vì vậy, hãy chắc chắn để làm điều này! ví dụ: grid[name] = {};
Jason Pudzianowski

1
@Matt Có cách nào để có được obj.fred.apples chỉ bằng một bộ [] không? Tôi cho rằng không. obj["fred.apples"]ví dụ
theB3RV

Điều gì xảy ra nếu chúng tôi không biết số lượng mảng, ví dụ như mã của bạn [javasript] var people = ['fred', 'alice']; var fruit = ['táo', 'chanh']; var color = [ 'đỏ', 'xanh'] var ..... -> số của mảng là chưa biết [/ javascript]
YukiSakura

Tôi có thể truy cập mục đầu tiên trong obj (fred) bằng chỉ mục số không? Giống như obj [0], kết quả là táo: 1, cam: 2. Tôi có thể truy cập mục cuối cùng (là alice và kết quả là chanh: 1) không? '
Timo

26

Nếu nó không phải là một mảng, bạn có thể tạo một đối tượng JS "đa chiều" ...

<script type="text/javascript">
var myObj = { 
    fred: { apples: 2, oranges: 4, bananas: 7, melons: 0 }, 
    mary: { apples: 0, oranges: 10, bananas: 0, melons: 0 }, 
    sarah: { apples: 0, oranges: 0, bananas: 0, melons: 5 } 
}

document.write( myObject[ 'fred' ][ 'apples' ] );
</script>

JSON thực sự là định dạng 'được chuỗi hóa' của đối tượng JavaScript. Những gì bạn có không có JSON, chỉ là một đối tượng JavaScript.
Matt

Cảm ơn, Matt. Đã cập nhật bài đăng.
charliegriefer

1
@charliegriefer, dòng document.write không nên là: "document.write (myObj ......"
john

13

Javascript rất linh hoạt:

var arr = {
  "fred": {"apple": 2, "orange": 4},
  "mary": {}
  //etc, etc
};

alert(arr.fred.orange);
alert(arr["fred"]["orange"]);
for (key in arr.fred)
    alert(key + ": " + arr.fred[key]);

8
Tôi sẽ nói tên biến 'arr' là một từ nhầm lẫn ở đây, bởi vì nó thực sự không phải là một mảng mà là một đối tượng.
Matt

Tôi là một con chó lười biếng và do đó không thể sử dụng giải pháp của bạn. Nếu tôi háo hức, tôi sẽ tìm ra cách của tôi với ví dụ về mảng con của bạn;) Dù sao, cảm ơn vì nỗ lực của bạn.
Timo

9

Khi tôi cần lấy tất cả các phần tử theo một cách tốt đẹp, tôi đã gặp chủ đề SO này "Chuyển ngang mảng / đối tượng kết hợp 2 chiều" - bất kể tên đối với tôi là gì, bởi vì chức năng được tính.

var imgs_pl = { 
    'offer':        { 'img': 'wer-handwritter_03.png', 'left': 1, 'top': 2 },
    'portfolio':    { 'img': 'wer-handwritter_10.png', 'left': 1, 'top': 2 },
    'special':      { 'img': 'wer-handwritter_15.png', 'left': 1, 'top': 2 }
};
for (key in imgs_pl) { 
    console.log(key);
    for (subkey in imgs_pl[key]) { 
        console.log(imgs_pl[key][subkey]);
    }
}

Câu trả lời nên được chấp nhận vì một vòng lặp thường là con đường để đi.
Timo

5

Dường như đối với một số ứng dụng, có một cách tiếp cận đơn giản hơn nhiều đối với mảng liên kết đa chiều trong javascript.

  1. Giả sử rằng biểu diễn bên trong của tất cả các mảng thực sự là đối tượng của các đối tượng, nó đã được chứng minh rằng thời gian truy cập cho các phần tử được lập chỉ mục số thực sự giống như đối với các phần tử được lập chỉ mục liên kết (văn bản).

  2. thời gian truy cập cho các phần tử được lập chỉ mục liên kết cấp một không tăng khi số lượng phần tử thực tế tăng lên.

Do đó, có thể có nhiều trường hợp tốt hơn là sử dụng cách tiếp cận chuỗi nối để tạo ra sự tương đương của các phần tử nhiều chiều. Ví dụ:

store['fruit']['apples']['granny']['price] = 10
store['cereal']['natural']['oats']['quack'] = 20

đi đến:

store['fruit.apples.granny.price'] = 10
store['cereal.natural.oats.quack'] = 20

Ưu điểm bao gồm:

  • không cần khởi tạo các đối tượng con hoặc tìm ra cách kết hợp các đối tượng tốt nhất
  • thời gian truy cập một cấp. các đối tượng bên trong các đối tượng cần N lần thời gian truy cập
  • có thể sử dụng Object.keys () để trích xuất tất cả thông tin về thứ nguyên và ..
  • có thể sử dụng hàm regex.test (chuỗi) và hàm array.map trên các phím để lấy ra chính xác những gì bạn muốn.
  • không có thứ bậc trong các kích thước.
  • "dấu chấm" là tùy ý - sử dụng dấu gạch dưới thực sự làm cho regex dễ dàng hơn
  • có rất nhiều tập lệnh để "làm phẳng" JSON thành và ra khỏi định dạng này
  • có thể sử dụng tất cả các hàm xử lý mảng đẹp mắt khác trên keylist

3

Nhận giá trị cho một mảng thuộc tính của mảng kết hợp khi tên thuộc tính là một số nguyên:

Bắt đầu với Mảng liên kết trong đó tên thuộc tính là số nguyên:

var categories = [
    {"1":"Category 1"},
    {"2":"Category 2"},
    {"3":"Category 3"},
    {"4":"Category 4"}
];

Đẩy các mục vào mảng:

categories.push({"2300": "Category 2300"});
categories.push({"2301": "Category 2301"});

Lặp qua mảng và làm điều gì đó với giá trị thuộc tính.

for (var i = 0; i < categories.length; i++) {
    for (var categoryid in categories[i]) {
        var category = categories[i][categoryid];
        // log progress to the console
        console.log(categoryid + " : " + category);
        //  ... do something
    }
}

Đầu ra của bảng điều khiển sẽ giống như sau:

1 : Category 1
2 : Category 2
3 : Category 3
4 : Category 4
2300 : Category 2300
2301 : Category 2301

Như bạn thấy, bạn có thể vượt qua giới hạn mảng kết hợp và đặt tên thuộc tính là một số nguyên.

LƯU Ý: Mảng kết hợp trong ví dụ của tôi là json bạn sẽ có nếu bạn tuần tự hóa một đối tượng Dictionary [].


3

Đừng sử dụng một mảng, hãy sử dụng một đối tượng.

var foo = new Object();

2
không sử dụng a new Object(), vì Object.prototype có thể có sự kỳ lạ gắn liền với nó; sử dụng đối tượng theo nghĩa đen:var foo = {};
Michael Paulukonis

1
@Michael Tôi nghĩ {} chỉ là đường cú pháp cho Object mới (); Giống như [] là viết tắt của Array mới ()
Matt

1
từ bảng điều khiển Chrome JS của tôi, cả hai cấu trúc này trông giống hệt nhau, bao gồm cả nguyên mẫu của chúng. Ngay cả việc thêm Object.prototype.foo = function () {} cũng xuất hiện trong cả hai.
Matt

1
@Matt Tôi nghĩ rằng tôi đã nhầm, tôi đã trộn lẫn với new Array()điều đó nên tránh. ugh.
Michael Paulukonis

1
@Michael tại sao nên tránh Array () mới?
Matt

2

Bạn không nhất thiết phải sử dụng Đối tượng, bạn có thể làm điều đó với Mảng đa chiều thông thường.

Đây là giải pháp của tôi mà không có Đối tượng :

// Javascript
const matrix = [];

matrix.key1 = [
  'value1',
  'value2',
];

matrix.key2 = [
  'value3',
];

trong PHP tương đương với:

// PHP
$matrix = [
    "key1" => [
        'value1',
        'value2',
    ],
    "key2" => [
        'value3',
    ]
];

1
Làm thế nào để bạn lặp lại (sử dụng từng) điều này sau này?
Sagive SEO

0

<script language="javascript">

// Set values to variable
var sectionName = "TestSection";
var fileMap = "fileMapData";
var fileId = "foobar";
var fileValue= "foobar.png";
var fileId2 = "barfoo";
var fileValue2= "barfoo.jpg";

// Create top-level image object
var images = {};

// Create second-level object in images object with
// the name of sectionName value
images[sectionName] = {};

// Create a third level object
var fileMapObj = {};

// Add the third level object to the second level object
images[sectionName][fileMap] = fileMapObj;

// Add forth level associate array key and value data
images[sectionName][fileMap][fileId] = fileValue;
images[sectionName][fileMap][fileId2] = fileValue2;


// All variables
alert ("Example 1 Value: " + images[sectionName][fileMap][fileId]);

// All keys with dots
alert ("Example 2 Value: " + images.TestSection.fileMapData.foobar);

// Mixed with a different final key
alert ("Example 3 Value: " + images[sectionName]['fileMapData'][fileId2]);

// Mixed brackets and dots...
alert ("Example 4 Value: " + images[sectionName]['fileMapData'].barfoo);

// This will FAIL! variable names must be in brackets!
alert ("Example 5 Value: " + images[sectionName]['fileMapData'].fileId2);
// Produces: "Example 5 Value: undefined".

// This will NOT work either. Values must be quoted in brackets.
alert ("Example 6 Value: " + images[sectionName][fileMapData].barfoo);
// Throws and exception and stops execution with error: fileMapData is not defined

// We never get here because of the uncaught exception above...
alert ("The End!");
</script>


0
    var myObj = [];
    myObj['Base'] = [];
    myObj['Base']['Base.panel.panel_base'] = {ContextParent:'',ClassParent:'',NameParent:'',Context:'Base',Class:'panel',Name:'panel_base',Visible:'',ValueIst:'',ValueSoll:'',
                                              Align:'',  AlignFrom:'',AlignTo:'',Content:'',onClick:'',Style:'',content_ger_sie:'',content_ger_du:'',content_eng:'' };
    myObj['Base']['Base.panel.panel_top']  = {ContextParent:'',ClassParent:'',NameParent:'',Context:'Base',Class:'panel',Name:'panel_base',Visible:'',ValueIst:'',ValueSoll:'',
                                              Align:'',AlignFrom:'',AlignTo:'',Content:'',onClick:'',Style:'',content_ger_sie:'',content_ger_du:'',content_eng:'' };

    myObj['SC1'] = [];
    myObj['SC1']['Base.panel.panel_base'] = {ContextParent:'',ClassParent:'',NameParent:'',Context:'Base',Class:'panel',Name:'panel_base',Visible:'',ValueIst:'',ValueSoll:'',
                                              Align:'',  AlignFrom:'',AlignTo:'',Content:'',onClick:'',Style:'',content_ger_sie:'',content_ger_du:'',content_eng:'' };
    myObj['SC1']['Base.panel.panel_top']  = {ContextParent:'',ClassParent:'',NameParent:'',Context:'Base',Class:'panel',Name:'panel_base',Visible:'',ValueIst:'',ValueSoll:'',
                                              Align:'',AlignFrom:'',AlignTo:'',Content:'',onClick:'',Style:'',content_ger_sie:'',content_ger_du:'',content_eng:'' };


    console.log(myObj);

    if ('Base' in myObj) {
      console.log('Base found');

      if ('Base.panel.panel_base' in myObj['Base'])  {
        console.log('Base.panel.panel_base found'); 


      console.log('old value: ' + myObj['Base']['Base.panel.panel_base'].Context);  
      myObj['Base']['Base.panel.panel_base'] = 'new Value';
      console.log('new value: ' + myObj['Base']['Base.panel.panel_base']);
      }
    }

Đầu ra:

  • Cơ sở được tìm thấy
  • Đã tìm thấy Base.panel.panel_base
  • giá trị cũ: Cơ sở
  • giá trị mới: Giá trị mới

Hoạt động của mảng hoạt động. Không có vấn đề gì cả.

Lặp lại:

     Object.keys(myObj['Base']).forEach(function(key, index) {            
        var value = objcons['Base'][key];                   
      }, myObj);

2
Chào mừng bạn đến với stackoverflow. Vui lòng chỉnh sửa câu trả lời của bạn và giải thích lý do tại sao các đoạn mã của bạn giải quyết được vấn đề. Thông tin thêm ở đây: Làm thế nào để trả lời
Djensen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.