Làm thế nào để giao tiếp thứ tự chèn đó quan trọng trong bản đồ?


24

Tôi đang tìm nạp một bộ dữ liệu từ cơ sở dữ liệu và đưa nó vào bản đồ. Các truy vấn cơ sở dữ liệu là tốn kém.

Không có thứ tự tự nhiên rõ ràng của các yếu tố trong bản đồ, tuy nhiên thứ tự chèn vẫn là vấn đề. Sắp xếp bản đồ sẽ là một hoạt động nặng nề, vì vậy tôi muốn tránh làm điều đó, với điều kiện là kết quả truy vấn đã được sắp xếp theo cách tôi muốn. Do đó, tôi chỉ lưu trữ kết quả truy vấn vào a LinkedHashMapvà trả về bản đồ từ phương thức DAO:

public LinkedHashMap<Key, Value> fetchData()

Tôi có một phương pháp processDatanên thực hiện một số xử lý trên bản đồ - sửa đổi một số giá trị, thêm một số khóa / giá trị mới. Nó được định nghĩa là

public void processData(LinkedHashMap<Key, Value> data) {...}

Tuy nhiên, một số linters (Sonar, v.v.) phàn nàn rằng Loại 'dữ liệu' phải là một giao diện như 'Bản đồ' thay vì triển khai "LinkedHashMap" ( mực S1319 ).
Vì vậy, về cơ bản nó đang nói rằng tôi nên có

public void processData(Map<Key, Value> data) {...}

Nhưng tôi muốn chữ ký phương thức nói rằng thứ tự bản đồ có vấn đề - nó quan trọng đối với thuật toán trong processData- để phương thức của tôi không được thông qua bất kỳ bản đồ ngẫu nhiên nào.

Tôi không muốn sử dụng SortedMap, bởi vì nó (từ javadoc củajava.util.SortedMap ) "được sắp xếp theo thứ tự tự nhiên của các khóa hoặc theo Công cụ so sánh thường được cung cấp tại thời điểm tạo bản đồ được sắp xếp."

Các khóa của tôi không có thứ tự tự nhiên và tạo Bộ so sánh để không làm gì có vẻ dài dòng.

Và tôi vẫn muốn nó là một bản đồ, tận dụng putđể tránh các khóa trùng lặp, v.v. Nếu không, datacó thể là một List<Map.Entry<Key, Value>>.

Vậy làm thế nào để tôi nói rằng phương pháp của tôi muốn một bản đồ đã được sắp xếp ? Đáng buồn thay, không có java.util.LinkedMapgiao diện, hoặc tôi sẽ sử dụng nó.

Câu trả lời:


56

Vì vậy, sử dụng LinkedHashMap.

, bạn nên sử dụng Mapqua một triển khai cụ thể bất cứ khi nào có thể, và vâng , đây cách thực hành tốt nhất.

Điều đó nói rằng, đây là một tình huống cụ thể kỳ lạ trong đó việc thực hiện các Mapvấn đề thực sự. Điều này sẽ không đúng với 99,9% trường hợp trong mã của bạn khi bạn sử dụng Map, nhưng bạn vẫn ở đây, trong tình huống 0,1% này. Sonar không thể biết điều này và vì vậy Sonar chỉ đơn giản là bảo bạn tránh sử dụng cách triển khai cụ thể vì nó sẽ đúng trong hầu hết các trường hợp.

Tôi sẽ lập luận rằng nếu bạn có thể tạo ra một trường hợp để sử dụng một triển khai cụ thể, đừng cố gắng đặt son môi lên một con lợn. Bạn cần một LinkedHashMap, không phải a Map.

Điều này nói rằng, nếu bạn chưa quen với lập trình và vấp phải câu trả lời này, đừng nghĩ rằng điều này cho phép bạn đi ngược lại thực tiễn tốt nhất bởi vì nó không. Nhưng khi thay thế một triển khai này sang một triển khai khác không được chấp nhận, điều duy nhất bạn có thể làm là sử dụng triển khai cụ thể đó và bị nguyền rủa đối với Sonar.


1
Cách tiếp cận thực dụng, mà tôi thích.
Vidar S. Ramdal

20
Tôi đồng ý gần như hoàn toàn với câu trả lời. Tôi chỉ muốn nói rằng bạn không nguyền rủa Sonar. Bạn luôn có thể định cấu hình nó để bỏ qua lỗi / cảnh báo cụ thể đó. Xem stackoverflow.com/questions/10971968/ cường
Vladimir Stokic

11
if you are new to programming and stumble upon this answer, don't think this allows you to go against best practice because it doesn't.- Lời khuyên tốt, nếu có một thứ gọi là "thực hành tốt nhất". Lời khuyên tốt hơn: học cách đưa ra quyết định đúng đắn. Thực hiện theo thực tiễn nếu nó có ý nghĩa, nhưng hãy để các công cụ và chính quyền hướng dẫn quá trình suy nghĩ của bạn, không sai khiến nó.
Robert Harvey

13
Lưu ý: khi sonar báo cáo cho bạn một cái gì đó, bạn có thể đóng nó thành "sẽ không được giải quyết" và để lại một ghi chú như tại sao bạn sẽ không. Như vậy, không chỉ sonar sẽ dừng lại để làm phiền bạn, mà bạn sẽ có một dấu vết về lý do tại sao bạn làm điều đó.
Walfrat

2
Tôi nghĩ khía cạnh làm cho điều này trở thành một ngoại lệ đối với nguyên tắc chung là LinkedHashMap có một hợp đồng dành riêng cho việc triển khai đó và không được thể hiện trong bất kỳ giao diện nào. Đây không phải là trường hợp thông thường. Vì vậy, cách duy nhất để thể hiện sự phụ thuộc vào hợp đồng đó là sử dụng loại thực hiện.
Dana

21

Bạn đang chiến đấu ba điều:

Đầu tiên là thư viện container của Java. Không có gì trong phân loại của nó cung cấp cho bạn một cách để xác định xem lớp có lặp lại theo thứ tự dự đoán hay không. Không có IteratesInInsertedOrderMapgiao diện nào có thể được thực hiện bằng LinkedHashMap, điều này làm cho việc kiểm tra kiểu (và việc sử dụng các triển khai thay thế hoạt động theo cùng một cách) là không thể. Đó có lẽ là do thiết kế, bởi vì tinh thần của nó là bạn thực sự có khả năng đối phó với các đối tượng hoạt động như trừu tượng Map.

Thứ hai là một niềm tin rằng những gì người nói dối của bạn nói phải được coi là phúc âm và bỏ qua bất cứ điều gì nó nói là xấu. Trái ngược với những gì được thông qua để thực hành tốt những ngày này, cảnh báo kẻ nói dối không được coi là rào cản để gọi mã của bạn là tốt. Họ nhắc nhở lý do về mã bạn đã viết và sử dụng kinh nghiệm và phán đoán của bạn để xác định xem cảnh báo có hợp lý hay không. Các cảnh báo không chính đáng là lý do tại sao hầu hết mọi công cụ phân tích tĩnh đều cung cấp một cơ chế để thông báo rằng bạn đã kiểm tra mã, bạn nghĩ rằng những gì bạn đang làm là ổn và họ không nên phàn nàn về nó trong tương lai.

Thứ ba, và đây có lẽ là thịt của nó, LinkedHashMapcó thể là công cụ sai cho công việc. Bản đồ được dành cho truy cập ngẫu nhiên, không theo thứ tự. Nếu processData()chỉ đơn giản lặp lại các bản ghi theo thứ tự và không cần tìm các bản ghi khác theo khóa, thì bạn buộc phải thực hiện cụ thể Mapđể thực hiện công việc của a List. Mặt khác, nếu bạn yêu cầu cả hai, LinkedHashMaplà công cụ phù hợp bởi vì nó được biết là làm những gì bạn muốn và bạn sẽ hợp lý hơn khi yêu cầu nó.


2
"LinkedHashMap có thể là công cụ sai cho công việc". Có lẽ. Khi tôi nói tôi cần OrderedMap, tôi cũng có thể nói như vậy UniqueList. Miễn là nó là một loại bộ sưu tập với thứ tự lặp được xác định, sẽ ghi đè lên các bản sao khi chèn.
Vidar S. Ramdal

2
@ VidarS.Ramdal Truy vấn cơ sở dữ liệu sẽ là nơi lý tưởng để loại bỏ các bản sao. Nếu cơ sở dữ liệu của bạn không thể làm điều đó, bạn luôn có thể giữ tạm thời Setcác khóa trong khi bạn xây dựng danh sách như một cách để phát hiện ra chúng.
Blrfl

Ồ, tôi thấy tôi đã gây ra nhầm lẫn. Có, kết quả truy vấn cơ sở dữ liệu không chứa các bản sao. Nhưng processDatasửa đổi bản đồ, thay thế một số giá trị, giới thiệu một số khóa / giá trị mới. Vì vậy, processDatacó thể giới thiệu các bản sao nếu nó đang hoạt động trên một cái gì đó khác hơn là a Map.
Vidar S. Ramdal

7
@ VidarS.Ramdal: Có vẻ như bạn cần phải viết UniqueList(hoặc OrderedUniqueList) của riêng bạn và sử dụng nó. Nó khá dễ dàng và làm cho mục đích sử dụng của bạn rõ ràng hơn.
TMN

2
@TMN Vâng, tôi đã bắt đầu suy nghĩ theo hướng đó. Nếu bạn muốn gửi đề xuất của bạn như một câu trả lời, nó chắc chắn sẽ nhận được upvote của tôi.
Vidar S. Ramdal

15

Nếu tất cả những gì bạn nhận được LinkedHashMaplà khả năng ghi đè lên các bản sao, nhưng bạn thực sự sử dụng nó như một List, thì tôi khuyên bạn nên giao tiếp việc sử dụng đó với Listviệc triển khai tùy chỉnh của riêng bạn . Bạn có thể dựa trên lớp bộ sưu tập Java hiện có và chỉ cần ghi đè bất kỳ addremovephương thức nào để cập nhật kho lưu trữ sao lưu của bạn và theo dõi khóa để đảm bảo tính duy nhất. Đặt tên này như một cái tên đặc biệt ProcessingListsẽ làm rõ rằng các đối số được trình bày cho processDataphương thức của bạn cần được xử lý theo một cách cụ thể.


5
Đây có thể là một ý tưởng tốt. Heck, bạn thậm chí có thể có một tệp một dòng tạo ra ProcessingListbí danh LinkedHashMap- bạn luôn có thể quyết định thay thế nó bằng một cái gì đó khác, miễn là bạn giữ nguyên giao diện công khai.
CompuChip

11

Tôi nghe bạn nói rằng "Tôi có một phần trong hệ thống của mình tạo ra LinkedHashMap và trong một phần khác trong hệ thống của tôi, tôi chỉ cần chấp nhận các đối tượng LinkedHashMap được sản xuất bởi phần đầu tiên, vì những phần được tạo bởi một quá trình khác đã thắng ' t hoạt động chính xác. "

Điều đó khiến tôi nghĩ rằng vấn đề ở đây thực sự là bạn đang cố gắng sử dụng LinkedHashMap vì nó hầu như phù hợp với dữ liệu bạn đang tìm kiếm, nhưng thực tế nó không thể được thay thế bằng bất kỳ trường hợp nào khác ngoài những trường hợp bạn tạo. Những gì bạn thực sự muốn làm là tạo giao diện / lớp của riêng bạn, đó là những gì phần đầu tiên của bạn tạo ra và phần thứ hai của bạn tiêu thụ. Nó có thể bao bọc LinkedHashMap "thực" và cung cấp một getter Map hoặc thực hiện giao diện Map.

Điều này hơi khác so với câu trả lời của CandiedOrange, ở chỗ tôi khuyên bạn nên đóng gói Bản đồ thực (và ủy thác các cuộc gọi cho nó khi cần thiết) thay vì mở rộng nó. Đôi khi, đó là một trong những cuộc chiến thần thánh theo phong cách đó, nhưng tôi chắc chắn rằng đó không phải là "Bản đồ với một số nội dung bổ sung", đó là "Túi thông tin trạng thái hữu ích của tôi, mà tôi có thể đại diện cho Bản đồ".

Nếu bạn có hai biến mà bạn cần phải vượt qua như thế này, có lẽ bạn đã tạo một lớp cho nó mà không cần suy nghĩ nhiều về nó. Nhưng đôi khi thật hữu ích khi có một lớp ngay cả khi đó chỉ là một biến thành viên, chỉ vì nó giống nhau về mặt logic, không phải là "giá trị" mà là "kết quả của hoạt động mà tôi cần thực hiện sau này".


Tôi thích suy nghĩ này - Tôi đã ở đó :) MyBagOfUsefulInformationsẽ cần một phương thức (hoặc hàm tạo) để điền vào nó : MyBagOfUsefulInformation.populate(SomeType data). Nhưng datasẽ cần phải là kết quả truy vấn được sắp xếp. Vì vậy, những gì sẽ SomeTypeđược, nếu không LinkedHashMap? Tôi không chắc là mình có thể phá được Catch 22.
Vidar S. Ramdal

Tại sao MyBagOfUsefulInformationDAO không thể được tạo hoặc bất cứ điều gì tạo ra dữ liệu trong hệ thống của bạn? Tại sao bạn cần phải hiển thị tất cả các bản đồ cơ bản cho phần còn lại của mã bên ngoài nhà sản xuất và người tiêu dùng của Túi?

Tùy thuộc vào kiến ​​trúc của bạn, bạn có thể sử dụng một hàm tạo riêng tư / được bảo vệ / chỉ gói để thực thi rằng đối tượng chỉ có thể được tạo bởi nhà sản xuất mà bạn muốn. Hoặc bạn có thể chỉ cần thực hiện nó như một quy ước, rằng nó chỉ có thể được tạo bởi "nhà máy" bên phải.

Vâng, cuối cùng tôi đã làm một cái gì đó tương tự, bằng cách chuyển MyBagOfUsefulInformationlàm tham số cho phương thức DAO: softwareengineering.stackexchange.com/a/360079/52573
Vidar S. Ramdal

4

LinkedHashMap là bản đồ java duy nhất có tính năng thứ tự chèn mà bạn đang tìm kiếm. Vì vậy, loại bỏ Nguyên tắc đảo ngược phụ thuộc là hấp dẫn và thậm chí có thể thực tế. Trước tiên, hãy xem xét những gì nó cần để làm theo nó. Đây là những gì RẮN sẽ yêu cầu bạn làm.

Lưu ý: thay thế tên Ramdalbằng một tên mô tả cho biết người tiêu dùng của giao diện này là chủ sở hữu của giao diện này. Điều này làm cho nó có thẩm quyền quyết định nếu thứ tự chèn là quan trọng. Nếu bạn chỉ gọi điều này InsertionOrderMapbạn đã thực sự bỏ lỡ điểm.

public interface Ramdal {
    //ISP asks for just the methods that processData() actually uses.
    ...
}

public class RamdalLinkedHashMap extends LinkedHashMap implements Ramdal{} 

Ramdal<Key, Value> ramdal = new RamdalLinkedHashMap<>();

ramdal.put(key1, value1);
ramdal.put(key2, value2);

processData(ramdal);

Đây có phải là một thiết kế lớn lên phía trước? Có thể, tùy thuộc vào khả năng bạn nghĩ rằng bạn sẽ cần triển khai bên cạnh LinkedHashMap. Nhưng nếu bạn không theo dõi chỉ vì nó sẽ là một nỗi đau lớn, tôi không nghĩ rằng tấm nồi hơi còn đau hơn thế này. Đây là mẫu tôi sử dụng khi tôi muốn mã không thể chạm tới được triển khai một giao diện mà nó không có. Phần đau đớn nhất thực sự là nghĩ về tên tốt.


2
Tôi thích cách đặt tên!
Vidar S. Ramdal

1

Cảm ơn rất nhiều gợi ý tốt và thực phẩm cho suy nghĩ.

Tôi đã kết thúc việc mở rộng tạo một lớp bản đồ mới, tạo processDatamột phương thức cá thể:

class DataMap extends LinkedHashMap<Key, Value> {

   processData();

}

Sau đó, tôi đã cấu trúc lại phương thức DAO để nó không trả về bản đồ mà thay vào đó lấy targetbản đồ làm tham số:

public void fetchData(Map<Key, Value> target) {
  ...
  // for each result row
  target.put(key, value);
}

Vì vậy, việc điền DataMapvà xử lý dữ liệu bây giờ là một quá trình gồm hai bước, điều này là tốt, vì có một số biến khác là một phần của thuật toán, xuất phát từ những nơi khác.

public DataMap fetchDataMap() {
  var dataMap = new DataMap();
  dao.fetchData(dataMap);
  return dataMap;
}

Điều này cho phép triển khai Bản đồ của tôi để kiểm soát cách các mục được chèn vào nó và ẩn đi yêu cầu đặt hàng - giờ đây là chi tiết triển khai của DataMap .


0

Nếu bạn muốn thông báo rằng cấu trúc dữ liệu bạn đã sử dụng là có lý do, hãy thêm một nhận xét phía trên chữ ký của phương thức. Nếu một nhà phát triển khác trong tương lai bắt gặp dòng mã này và thông báo cảnh báo công cụ, họ cũng có thể nhận thấy bình luận đó và không "sửa" vấn đề. Nếu không có bình luận, thì không có gì ngăn họ thay đổi chữ ký.

Việc ngăn chặn các cảnh báo kém hơn bình luận theo ý kiến ​​của tôi, bởi vì chính sự đàn áp không nêu rõ lý do tại sao cảnh báo bị đàn áp. Một sự kết hợp của ức chế cảnh báo và bình luận cũng sẽ tốt.


0

Vì vậy, hãy để tôi cố gắng hiểu bối cảnh của bạn ở đây:

... vấn đề thứ tự chèn ... Sắp xếp bản đồ sẽ là một hoạt động nặng nề ...

... kết quả truy vấn đã được sắp xếp theo cách tôi muốn

Bây giờ, những gì bạn đang làm:

Tôi đang tìm nạp một bộ dữ liệu từ cơ sở dữ liệu và đưa nó vào bản đồ ...

Và đây là mã hiện tại của bạn:

public void processData(LinkedHashMap<Key, Value> data) {...}

Đề nghị của tôi là làm như sau:

  • Sử dụng phép nội xạ phụ thuộc và tiêm một số MyTupleRep repository vào phương thức xử lý (MyTupleRep repository là một giao diện được thực hiện bởi các đối tượng truy xuất các đối tượng tuple của bạn, thường là từ DB);
  • nội bộ phương thức xử lý, đưa dữ liệu từ kho lưu trữ (còn gọi là DB, đã trả về dữ liệu đã đặt hàng) trong bộ sưu tập LinkedHashMap cụ thể, bởi vì đây là chi tiết bên trong của thuật toán xử lý (vì nó phụ thuộc vào cách sắp xếp dữ liệu trong cấu trúc dữ liệu );
  • Lưu ý rằng, đây là khá nhiều những gì bạn đã làm, nhưng trong trường hợp này, điều này sẽ được thực hiện trong phương thức xử lý. Kho lưu trữ của bạn được khởi tạo ở một nơi khác (bạn đã có một lớp trả về dữ liệu, đây là kho lưu trữ trong ví dụ này)

Mã ví dụ

public interface MyTupleRepository {
    Collection<MyTuple> GetAll();
}

//Concrete implementation of data access object, that retrieves 
//your tuples from DB; this data is already ordered by the query
public class DbMyTupleRepository implements MyTupleRepository { }

//Injects some abstraction of repository into the processing method,
//but make it clear that some exception might be thrown if data is not
//arranged in some specific way you need
public void processData(MyTupleRepository tupleRepo) throws DataNotOrderedException {

    LinkedHashMap<Key, Value> data = new LinkedHashMap<Key, Value>();

    //Represents the query to DB, that already returns ordered data
    Collection<MyTuple> myTuples = tupleRepo.GetAll();

    //Optional: this would throw some exception if data is not ordered 
    Validate(myTuples);

    for (MyTupleData t : myTuples) {
        data.put(t.key, t.value);
    }

    //Perform the processing using LinkedHashMap...
    ...
}

Tôi đoán điều này sẽ thoát khỏi cảnh báo Sonar, và cũng chỉ định trong bố cục cụ thể chữ ký của dữ liệu theo yêu cầu của phương thức xử lý.


Hmm, nhưng làm thế nào các kho lưu trữ sẽ được khởi tạo? Điều này sẽ không chuyển vấn đề sang một nơi khác (đến nơi MyTupleRepositoryđược tạo ra?)
Vidar S. Ramdal

Tôi nghĩ tôi sẽ gặp vấn đề tương tự như câu trả lời của Peter Cooper .
Vidar S. Ramdal

Đề nghị của tôi liên quan đến việc áp dụng Nguyên tắc tiêm phụ thuộc; trong ví dụ này; MyTupleRep repository là một giao diện xác định khả năng truy xuất các bộ dữ liệu bạn đã đề cập (truy vấn DB). Tại đây, bạn tiêm đối tượng này vào phương thức xử lý. Bạn đã có một số lớp trả về dữ liệu; điều này chỉ trừu tượng hóa nó trong một giao diện và bạn đưa đối tượng vào phương thức 'processData', bên trong sử dụng LinkedHashMap vì đây thực chất là một phần của quá trình xử lý.
Emerson Cardoso

Tôi đã chỉnh sửa câu trả lời của mình, cố gắng rõ ràng hơn về những gì tôi đang đề xuất.
Emerson Cardoso

-1

Câu hỏi này thực sự là một loạt các vấn đề với mô hình dữ liệu của bạn được đưa vào một. Bạn cần bắt đầu gỡ rối chúng, từng cái một. Các giải pháp trực quan, tự nhiên hơn sẽ xuất hiện khi bạn cố gắng đơn giản hóa từng mảnh ghép.

Vấn đề 1: Bạn không thể phụ thuộc vào Đơn hàng DB

Mô tả của bạn về sắp xếp dữ liệu của bạn là không rõ ràng.

  • Vấn đề tiềm năng lớn nhất là bạn không chỉ định một loại rõ ràng trong cơ sở dữ liệu của mình, thông qua một ORDER BYmệnh đề. Nếu bạn không phải vì nó quá đắt, chương trình của bạn có lỗi . Cơ sở dữ liệu được phép trả về kết quả theo bất kỳ thứ tự nào nếu bạn không chỉ định một kết quả; bạn không thể phụ thuộc vào nó một cách ngẫu nhiên trả lại dữ liệu theo thứ tự chỉ vì bạn đã chạy truy vấn một vài lần và nó trông như vậy. Thứ tự có thể thay đổi vì các hàng được sắp xếp lại trên đĩa hoặc một số bị xóa và các hàng mới thay thế chúng hoặc chỉ mục được thêm vào. Bạn phải chỉ định mộtORDER BY mệnh đề của một số loại. Tốc độ là vô giá trị mà không chính xác.
  • Nó cũng không rõ ý của bạn bằng cách chèn thứ tự quan trọng. Nếu bạn đang nói về chính cơ sở dữ liệu, bạn phải có một cột thực sự theo dõi điều này và nó phải được bao gồm trong ORDER BYmệnh đề của bạn . Nếu không, bạn có lỗi. Nếu một cột như vậy chưa tồn tại, thì bạn cần thêm một cột. Các tùy chọn điển hình cho các cột như thế này sẽ là cột dấu thời gian chèn hoặc khóa tăng tự động. Phím tăng tự động là đáng tin cậy hơn.

Vấn đề 2: Sắp xếp bộ nhớ hiệu quả

Một khi bạn chắc chắn rằng nó được đảm bảo để được trở về dữ liệu theo thứ tự bạn mong đợi, bạn có thể tận dụng thực tế này để thực hiện trong bộ nhớ các loại nhiều hiệu quả hơn. Chỉ cần thêm một row_number()hoặcdense_rank() cột (hoặc tương đương với cơ sở dữ liệu của bạn) vào tập kết quả truy vấn của bạn. Bây giờ mỗi hàng có một chỉ mục sẽ cung cấp cho bạn một dấu hiệu trực tiếp về thứ tự được cho là gì và bạn có thể sắp xếp theo thứ tự này trong bộ nhớ một cách tầm thường. Chỉ cần đảm bảo rằng bạn đặt cho chỉ mục một tên có ý nghĩa (nhưsortedBySomethingIndex ).

Viola. Bây giờ bạn không phải phụ thuộc vào thứ tự thiết lập kết quả cơ sở dữ liệu nữa.

Vấn đề 3: Bạn thậm chí có cần thực hiện xử lý này trong mã không?

SQL thực sự rất mạnh. Đó là một ngôn ngữ khai báo tuyệt vời cho phép bạn thực hiện nhiều biến đổi và tổng hợp trên dữ liệu của mình. Hầu hết các DB thậm chí còn hỗ trợ các hoạt động hàng ngang hiện nay. Chúng được gọi là chức năng cửa sổ hoặc phân tích:

Bạn thậm chí có cần phải kéo dữ liệu của mình vào bộ nhớ như thế này không? Hoặc bạn có thể thực hiện tất cả các công việc trong truy vấn SQL bằng cách sử dụng các hàm cửa sổ? Nếu bạn có thể làm tất cả (hoặc thậm chí chỉ là một phần quan trọng) của công việc trong DB, thật tuyệt vời!Vấn đề mã của bạn biến mất (hoặc đơn giản hơn rất nhiều)!

Vấn đề 4: Bạn đang làm gì với điều đó data ?

Giả sử bạn không thể làm tất cả trong DB, hãy để tôi nói thẳng điều này. Bạn đang lấy dữ liệu dưới dạng bản đồ (được khóa bởi những thứ bạn không muốn sắp xếp theo), sau đó bạn đang lặp lại dữ liệu theo thứ tự chèn và sửa đổi bản đồ tại chỗ bằng cách thay thế giá trị của một số khóa và thêm những cái mới?

Tôi xin lỗi, nhưng cái quái gì thế?

Người gọi không cần phải lo lắng về tất cả điều này . Hệ thống bạn đã tạo cực kỳ mong manh. Chỉ cần một sai lầm ngớ ngẩn (thậm chí có thể do chính bạn tạo ra, như chúng ta đã làm) để thực hiện một thay đổi nhỏ và toàn bộ sự việc sụp đổ như một cỗ bài.

Đây có thể là một ý tưởng tốt hơn:

  • Có chức năng của bạn chấp nhận một List .
  • Có một vài cách bạn có thể xử lý vấn đề đặt hàng.
    1. Áp dụng thất bại nhanh. Ném một lỗi nếu danh sách không theo thứ tự mà hàm yêu cầu. (Lưu ý: Bạn có thể sử dụng chỉ mục sắp xếp từ Bài toán 2 để biết nếu có.)
    2. Tự tạo một bản sao được sắp xếp (một lần nữa sử dụng chỉ mục từ vấn đề 2).
    3. Chỉ ra một cách để xây dựng bản đồ theo thứ tự.
  • Xây dựng bản đồ bạn cần nội bộ cho chức năng, vì vậy người gọi không cần phải quan tâm đến nó.
  • Bây giờ lặp đi lặp lại bất cứ điều gì theo thứ tự đại diện bạn có và làm những gì bạn phải làm.
  • Trả lại bản đồ hoặc chuyển đổi nó thành một giá trị trả về thích hợp

Một biến thể có thể có thể là xây dựng một biểu diễn được sắp xếp và sau đó tạo một bản đồ khóa để lập chỉ mục . Điều này sẽ cho phép bạn sửa đổi bản sao được sắp xếp của bạn tại chỗ, mà không vô tình tạo các bản sao.

Hoặc có thể điều này có ý nghĩa hơn: loại bỏ datatham số và thực processDatasự lấy dữ liệu của chính nó. Sau đó, bạn có thể ghi lại rằng bạn đang làm điều này bởi vì nó có các yêu cầu rất cụ thể về cách dữ liệu được tìm nạp. Nói cách khác, làm cho hàm riêng toàn bộ quá trình, không chỉ là một phần của nó; sự phụ thuộc lẫn nhau quá mạnh để phân chia logic thành các phần nhỏ hơn. (Thay đổi tên của hàm trong quy trình.)

Có lẽ những điều này sẽ không làm việc cho tình huống của bạn. Tôi không biết mà không có chi tiết đầy đủ của vấn đề. Nhưng tôi biết một thiết kế mỏng manh và khó hiểu khi tôi nghe.

Tóm lược

Tôi nghĩ vấn đề ở đây cuối cùng là ma quỷ nằm trong chi tiết. Khi tôi bắt đầu gặp rắc rối như thế này, thường là do tôi có cách trình bày dữ liệu không phù hợp cho vấn đề tôi đang cố gắng giải quyết. Giải pháp tốt nhất là tìm một đại diện tốt hơn , và sau đó vấn đề của tôi trở nên đơn giản (có thể không dễ dàng, nhưng đơn giản) để giải quyết.

Tìm ai đó đạt được điểm đó: công việc của bạn là giảm vấn đề của bạn xuống một tập hợp những vấn đề đơn giản, đơn giản. Sau đó, bạn có thể xây dựng mã mạnh mẽ, trực quan. Nói chuyện với họ. Mã tốt và thiết kế tốt khiến bạn nghĩ rằng bất kỳ kẻ ngốc nào cũng có thể nghĩ ra chúng, bởi vì chúng đơn giản và dễ hiểu. Có lẽ có một nhà phát triển cấp cao có tư duy mà bạn có thể nói chuyện.


"Ý bạn là gì không có thứ tự tự nhiên nhưng thứ tự chèn có vấn đề? Bạn có nói rằng vấn đề là thứ tự dữ liệu được chèn vào bảng DB, nhưng bạn không có cột nào có thể cho bạn biết thứ gì được chèn vào?" - câu hỏi nêu rõ: "Sắp xếp bản đồ sẽ là một hoạt động nặng nề, vì vậy tôi muốn tránh làm điều đó, với điều kiện là kết quả truy vấn đã được sắp xếp". Đây rõ ràng phương tiện đó có một trật tự nhất định calculatable số liệu, bởi vì nếu không sắp xếp nó sẽ là bất khả thi chứ không phải là nặng, nhưng điều đó tự quy định khác với quy luật tự nhiên của các phím.
Jules

2
Nói cách khác, OP đang làm việc dựa trên kết quả của một truy vấn như thế nào select key, value from table where ... order by othercolumnvà cần duy trì thứ tự trong quá trình xử lý của họ. Thứ tự chèn mà họ đang đề cập là thứ tự chèn vào bản đồ của họ , được xác định bởi thứ tự được sử dụng trong truy vấn của họ, chứ không phải thứ tự chèn vào cơ sở dữ liệu . Điều này được làm rõ bằng cách sử dụng chúng LinkedHashMap, đó là một cấu trúc dữ liệu có các đặc điểm cả a Mapvà của một Listcặp khóa-giá trị.
Jules

@Jules Tôi sẽ dọn sạch phần đó một chút, cảm ơn. (Tôi thực sự nhớ đã đọc nó, nhưng khi tôi kiểm tra mọi thứ trong khi viết câu hỏi, tôi không thể tìm thấy nó. Lol. Có quá nhiều cỏ dại.) Nhưng câu hỏi không rõ ràng về những gì họ đang làm với DB truy vấn và liệu họ có một loại rõ ràng hay không. Họ cũng nói rằng "vấn đề trật tự chèn." Vấn đề là ngay cả khi việc sắp xếp rất nặng nề, bạn không thể dựa vào DB để sắp xếp thứ tự một cách chính xác nếu bạn không nói rõ ràng. Và nếu bạn đang thực hiện nó trong DB, thì bạn có thể sử dụng một "chỉ mục" để làm cho nó hiệu quả trong mã.
jpmc26

* viết câu trả lời (Methinks Tôi nên đi ngủ sớm.)
jpmc26

Vâng, @Jules là đúng. Có một order byđiều khoản trong các truy vấn, nhưng nó là không tầm thường ( không chỉ order by column), vì vậy tôi muốn tránh reimplementing các sắp xếp trong Java. Mặc dù SQL rất mạnh (và chúng ta đang nói về cơ sở dữ liệu Oracle 11g ở đây), bản chất của processDatathuật toán làm cho việc diễn đạt bằng Java dễ dàng hơn nhiều. Và có, "thứ tự chèn" có nghĩa là " thứ tự chèn bản đồ ", tức là thứ tự kết quả truy vấn.
Vidar S. Ramdal
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.