2012-06-23 35 views
10

Tôi có một hashmap lớn chứa hàng triệu mục nhập và tôi muốn lưu nó vào đĩa, để khi nó được đọc từ đĩa một lần nữa, tôi không có chi phí chèn cặp khóa-giá trị trở lại vào bản đồ lần nữa.Làm thế nào để tuần tự hóa/deserialize một hashmap?

Tôi đang cố gắng sử dụng thư viện ngũ cốc để thực hiện việc này, nhưng có vẻ như kiểu dữ liệu HashMap cần lấy được Chung. Có cách nào để làm việc này không?

+0

Sự cố xảy ra với Generic là gì? – Cubic

+1

Để lấy được Generic, cho một kiểu tùy chỉnh, chúng tôi cần phải viết một cái gì đó như: 'Something data = Something Int Int bắt nguồn Generic' Làm thế nào điều này có thể được thực hiện nếu datatype là trong một thư viện trên Hackage (trừ nộp một bản vá cho người bảo trì của thư viện)? – donatello

+0

Hmm ...Vâng, cá nhân tôi nghi ngờ rằng Serializing HashMaps như thế này sẽ không hoạt động, và bạn sẽ phải sử dụng một triển khai khác hỗ trợ kiểu serialization mà bạn muốn, nhưng hãy xem những gì người khác nói. – Cubic

Trả lời

0

Hiện tại, không có cách nào để làm cho HashMap có thể tuần tự hóa mà không sửa đổi thư viện HashMap.

Không thể tạo Data.HashMap một thể hiện chung (để sử dụng với ngũ cốc) bằng cách sử dụng độc lập như được mô tả bởi câu trả lời @ mergeconflict, vì Data.HashMap không xuất tất cả các nhà xây dựng của nó (đây là yêu cầu cho GHC).

Vì vậy, giải pháp duy nhất còn lại để tuần tự hóa HashMap dường như là sử dụng giao diện toList/fromList.

5

Bạn có thể sử dụng stand-alone deriving để tạo ví dụ Generic của riêng mình cho HashMap. Bạn có thể sẽ nhận được một cảnh báo về orphan instances, nhưng bạn cũng có thể không quan tâm :) Dù sao, tôi đã không cố gắng này, nhưng nó có thể có giá trị một shot ...

+2

Tôi nghĩ đây là một câu trả lời hay. Một điểm nữa có lẽ là một mẹo về cách tránh các cá thể mồ côi: chỉ cần định nghĩa một kiểu mới bao bọc một HashMap và xác định cá thể cho kiểu này. Khi bạn cần phải serialize HashMap chỉ cần bọc nó trong loại của bạn và serialize. – Tener

+0

@mergeconflict, @Tener Tôi đã thêm một dòng: 'deriving instance (Generic k, Generic v) => Generic (H.HashMap kv)' Nhưng GHC phàn nàn rằng tất cả các nhà xây dựng dữ liệu của HashMap không nằm trong phạm vi (ví dụ: [chúng không phải là tất cả được xuất khẩu] (http://hackage.haskell.org/packages/archive/unordered-containers/0.2.1.0/doc/html/src/Data-HashMap-Base.html#HashMap)). Dường như cách tiếp cận này sẽ không hoạt động. donatello

+0

@donatello Bummer :( – mergeconflict

1

Tôi không chắc chắn nếu sử dụng Generics là một bức ảnh tốt nhất đạt được hiệu suất cao. đặt cược tốt nhất của tôi thực sự sẽ có văn bản dụ của riêng bạn cho Serializable như thế này:

instance (Serializable a) => Serializable (HashMap a) where 
    ... 

Để tránh tạo ra các trường hợp trẻ mồ côi, bạn có thể sử dụng Newtype lừa:

newtype SerializableHashMap a = SerializableHashMap { toHashMap :: HashMap a } 
instance (Serializable a) => SerializableHashMap a where 
    ... 

Câu hỏi đặt ra là làm thế nào để xác định ...?

Không có câu trả lời xác định trước khi bạn thực sự thử và triển khai và đánh giá các giải pháp có thể có.

Một giải pháp có thể là sử dụng các chức năng toList/fromList và lưu trữ/đọc kích thước của HashMap.

Loại khác (tương tự như sử dụng Generics) sẽ viết chuỗi tuần tự trực tiếp dựa trên cấu trúc HashMap bên trong. Do thực tế là bạn không thực sự có các internals xuất khẩu mà sẽ là một công việc cho Generics chỉ.

0

Nếu bạn có thể sử dụng hệ nhị phân, có nhị phân-trẻ mồ côi mà cung cấp ví dụ cho có thứ tự-ten-nơ. Tôi không thể cài đặt trẻ mồ côi nhị phân do một số xung đột về cabal, nhưng chỉ cần giật các phần tôi cần, ví dụ:

{-# LANGUAGE CPP   #-} 
{-# LANGUAGE DeriveGeneriC#-} 

module Bin where 

import   Data.Binary 
import   Data.ByteString.Lazy.Internal 
import   Data.Hashable     (Hashable) 
import qualified Data.HashMap.Strict   as M 
import qualified Data.Text      as T 

#if !(MIN_VERSION_text(1,2,1)) 
import   Data.Text.Binary    () 
#endif 

instance (Hashable k, Eq k, Binary k, Binary v) => Binary (M.HashMap k v) where 
    get = fmap M.fromList get 
    put = put . M.toList 

-- Note: plain `encode M.fromList []` without type annotations won't work 
encodeModel :: M.HashMap T.Text Int -> ByteString 
encodeModel m = 
    encode m 
Các vấn đề liên quan