Y và X - Tôi có làm sai không?


8

Đôi khi tôi gặp phải các vấn đề nhỏ khi thực hiện các dự án JavaScript của mình. Đó là bởi vì hầu hết các chức năng xây dựng của JavaScript đều chạy X, Y nếu cần các vị trí. (Theo thứ tự đó).

Nhưng khi tôi xây dựng một mảng 2D tôi bắt đầu với Y, có vẻ hợp lý hơn đối với tôi khi chạy trục X ngang. Nếu tôi không tốt trong việc giải thích nó, hãy để tôi chỉ cho bạn:

nhập mô tả hình ảnh ở đây

Vì vậy, các vòng lặp của tôi trông như thế này:

for(var y = 0; y < 10; y++){
    for(var x = 0; x < 10; x++){
        console.log("Doh!");
    }
}

Đây có phải là rất điên rồ? Tôi muốn chuyển đổi sang thực tiễn thông thường để tôi có thời gian dễ dàng hơn trong khi xây dựng trò chơi của mình và không phải thực hiện chuyển đổi liên tục.

Vậy tại sao lại là X trước Y?

Chỉnh sửa: Đây là một ví dụ khác và có lẽ là lý do chính khiến tôi nhầm lẫn: X là Ngang và Y là Dọc trong sách của tôi ..

[
[0,1,2,3,4],
[0,1,2,3,4],
[0,1,2,3,4],
[0,1,2,3,4],
]

3
Bản năng đầu tiên của tôi sẽ là vì chúng tôi dán nhãn các điểm như (X, Y) trên mặt phẳng Cartesian.
Vaughan Hilts

Tôi đoán vậy, nhưng nhìn vào mảng ví dụ mới của tôi. Có vẻ đúng hơn với tôi theo cách đó
Oliver Schöning

Câu trả lời:


8

Không, nếu nó hiệu quả với bạn, bạn đã không làm sai. Nếu bạn muốn chuyển đổi, hơn làm như vậy. Thứ tự bạn xử lý hàng / cột đôi khi là tùy ý, đôi khi không. Thứ tự bạn sử dụng phụ thuộc hoàn toàn vào thuật toán bạn đang sử dụng.

Có nhiều kết hợp khác nhau để xử lý X, Y. Tùy thuộc vào bạn để chọn cái nào là chính xác cho thuật toán của bạn. Trong trường hợp mỗi lần lặp độc lập với bất kỳ lần lặp nào khác, bạn có thể chọn bất kỳ lần nào bạn muốn. Bạn có thể chuyển đổi trong vòng lặp bên trong và bạn cũng có thể chuyển đổi nếu các vòng lặp đi từ min đến max hoặc max sang min.

Tôi tưởng tượng mặc định là:

for xmin to xmax
    for ymin to ymax

bởi vì đây thường là cách dữ liệu được sắp xếp trong bộ nhớ. (Không nhất thiết đúng với tất cả các ngôn ngữ vì thứ tự của chỉ mục có thể thay đổi).

Ví dụ: một mảng A[3][3]( A[X][Y]):

nhập mô tả hình ảnh ở đây

Trong đó ygiá trị nằm trong vòng lặp bên trong tăng trước và sau đó "cuộn qua" để tăng xgiá trị. Ngoài ra, (X, Y) là cách tiêu chuẩn để viết nó trong toán học.


Chúc mừng, nó chỉ "có vẻ đúng" khi tôi đang xây dựng một lưới:
Oliver Schöning

4

Bạn đang làm sai ... loại. Điều sai bạn đang làm là tương quan thứ tự các tọa độ được viết với thứ tự các vòng lặp được lồng vào nhau. Đó là những ý tưởng hoàn toàn khác nhau!

Cụ thể hơn, điều sai lầm là hệ thống tọa độ của bạn bị ràng buộc theo một cách mạnh mẽ (và dễ vỡ) để bạn thực hiện lưu trữ dữ liệu của mình. Điều đó có nghĩa là bạn đang thiết kế mã xấu theo quan điểm OO. Việc lưu trữ dữ liệu phải mờ đục đối với thứ sử dụng nó và thứ sử dụng nó không nên quan tâm đến việc dữ liệu được lưu trữ như thế nào. Người sử dụng dữ liệu chỉ cần biết làm thế nào để có được phần thông tin mà nó muốn.

Những gì bạn nên làm là tìm cách trừu tượng hóa cấu trúc dữ liệu mảng lồng nhau của bạn và ẩn nó trong một phương thức như thế nào getPoint(x,y). Sau đó, bạn không phải lo lắng về mảng nào được lồng theo thứ tự nào. Bạn có thể để cấu trúc dữ liệu ngược của mình chính xác, miễn là phương thức getter của bạn biết trước tiên tìm mảng y, sau đó tìm kiếm bên trong nó cho phần tử x. Nhưng bất cứ mã nào đang gọi getPoint()đều không biết điều đó. Nó chỉ cần biết hai tọa độ mà nó quan tâm.


Nói cách khác: "Các chương trình không quan tâm mã của bạn đẹp đến mức nào!"
Oliver Schöning

Nhưng có gì sai với cách lưu trữ của tôi ngoài việc bị lộn ngược?
Oliver Schöning

Không, tôi không nghĩ vậy; các câu trả lời khác là đúng theo cách đó. Quan điểm của tôi chỉ là về cách nó gây ra sự nhầm lẫn cho bạn, điều mà tôi đã suy ra từ thực tế mà bạn hỏi. Nếu việc triển khai của bạn làm cho mã của bạn khó hiểu, thì hãy gói gọn sự kỳ lạ đó đằng sau một giao diện tốt và quên nó đi.
Seth Battin

1

Không quan trọng! Tôi cũng luôn viết Y trước (trông tự nhiên hơn). Khi bạn có ma trận của bạn trong mảng dưới dạng các hàng, bạn thậm chí có thể thực hiện một số tối ưu hóa. Thay vì điều này:

for(var y=0; y<h; y++){
    for(var x=0; x<w; x++){
        m[y*w+x] = a;
    }
}

bạn có thể sử dụng cái này:

for(var y=0; y<h; y++){
    var i = y*w;
    for(var x=0; x<w; x++, i++){
        m[i] = a;
    }
}

và tránh nhiều phép nhân! :)


Bạn có thể cho tôi biết ví dụ thứ hai của bạn làm tốt hơn? : o Trong JavaScript không có mảng 2D "thực", bạn phải tạo một mảng các mảng. Do đó, tôi không biết nếu tôi có thể sử dụng ví dụ thứ hai.
Oliver Schöning

Giả sử, w = h = 1000. Trong ví dụ đầu tiên, bạn đang nhân 1000000 phép nhân, trong khi trong ví dụ thứ hai, bạn chỉ thực hiện 1000 phép nhân. Phép nhân là cực khó, nhiều CPU thậm chí không có lệnh nhân. Họ đang mô phỏng nó với các phép toán cộng và bit.
Ivan Kuckir

Tôi hiểu rồi. Nhưng tôi không thấy mình làm như vậy. Của tôi thường trông như thế này: for (var y ...) {mảng [y] = [] for (var x ...) {mảng [y] [x] = a;}}
Oliver Schöning

1
Ồ chắc chắn rồi. Nhưng bạn đang tạo 1000 đối tượng JS mới trên heap ... ồ, đừng
bận
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.