Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 查找最频繁项的最有效数据结构_Sorting_Haskell_Data Structures_Word Frequency - Fatal编程技术网

Sorting 查找最频繁项的最有效数据结构

Sorting 查找最频繁项的最有效数据结构,sorting,haskell,data-structures,word-frequency,Sorting,Haskell,Data Structures,Word Frequency,我想从中提取最频繁的单词,它的未压缩形式大约为20GB。我不想使用整个数据集,只想使用其中最频繁的5000个。但是如果我写 take 5000 $ sortBy (flip $ comparing snd) dataset -- dataset :: IO [(word::String, frequency::Int)] 这将是无休止的等待。但是我应该怎么做呢 我知道有一个包可用于就地数组计算,但我在其文档页面上看不到任何项修改函数。也有,但它是一个无序的数据结构 我想使用simple(使用它

我想从中提取最频繁的单词,它的未压缩形式大约为20GB。我不想使用整个数据集,只想使用其中最频繁的5000个。但是如果我写

take 5000 $ sortBy (flip $ comparing snd) dataset
-- dataset :: IO [(word::String, frequency::Int)]
这将是无休止的等待。但是我应该怎么做呢

我知道有一个包可用于就地数组计算,但我在其文档页面上看不到任何项修改函数。也有,但它是一个无序的数据结构

我想使用simple(使用它方便的
lookupLE
函数),但我不认为它会非常有效,因为它会在每次修改时生成一个新的映射。
ST
monad能改善这一点吗

UPD:我还将程序的最终版本发布在了上

怎么样

  • 使用
    splitAt
    将数据集划分为前5000个项目和其余项目
  • 按频率对前5000项进行排序(升序)
  • 过完剩下的
    • 如果某个项目的频率高于排序项目中的最低频率
    • 从已排序的项目中删除频率最低的项目
    • 将新项目插入已排序项目的适当位置
然后,该过程实际上变为线性,尽管如果对已排序的5000个元素使用具有次线性最小删除和插入的数据结构,则系数会得到改进

例如,使用:

导入数据列表(foldl')
导入数据。可能(fromJust)
导入数据。堆隐藏(拆分)
mostFreq::Int->[(字符串,Int)]->[(字符串,Int)]
mostFreq n数据集=最终
哪里
--将配对从(String,Int)更改为(Int,String)
pairs=映射交换数据集
--在一个列表中获取第一个'n'对,在另一个列表中获取其余的对
(第一,rest)=在n对处拆分
--将所有前'n'对放入一个碎纸堆中
start=fromList first::MinHeap(Int,String)
--然后跑完剩下的几对
停止=折叠“步进-开始-休息”
--修改堆以替换其最不频繁的堆对
--如果新配对更频繁,则使用新配对
步骤堆对=如果视图头堆<仅对
然后插入对(来自$viewTail堆)
其他堆
--将(Int,String)对的堆转换为(String,Int)对的列表
最终=地图交换(toList停止)
交换~(a,b)=(b,a)
怎么样

  • 使用
    splitAt
    将数据集划分为前5000个项目和其余项目
  • 按频率对前5000项进行排序(升序)
  • 过完剩下的
    • 如果某个项目的频率高于排序项目中的最低频率
    • 从已排序的项目中删除频率最低的项目
    • 将新项目插入已排序项目的适当位置
然后,该过程实际上变为线性,尽管如果对已排序的5000个元素使用具有次线性最小删除和插入的数据结构,则系数会得到改进

例如,使用:

导入数据列表(foldl')
导入数据。可能(fromJust)
导入数据。堆隐藏(拆分)
mostFreq::Int->[(字符串,Int)]->[(字符串,Int)]
mostFreq n数据集=最终
哪里
--将配对从(String,Int)更改为(Int,String)
pairs=映射交换数据集
--在一个列表中获取第一个'n'对,在另一个列表中获取其余的对
(第一,rest)=在n对处拆分
--将所有前'n'对放入一个碎纸堆中
start=fromList first::MinHeap(Int,String)
--然后跑完剩下的几对
停止=折叠“步进-开始-休息”
--修改堆以替换其最不频繁的堆对
--如果新配对更频繁,则使用新配对
步骤堆对=如果视图头堆<仅对
然后插入对(来自$viewTail堆)
其他堆
--将(Int,String)对的堆转换为(String,Int)对的列表
最终=地图交换(toList停止)
交换~(a,b)=(b,a)
您是否尝试过这一点,或者您只是在猜测?因为许多Haskell排序函数都尊重惰性,当您只要求前5000个时,它们会很高兴地避免对其余元素进行排序

同样,要非常小心“每次变更都会生成一张新地图”。在这种数据结构上,大多数插入操作都将是O(logn),n限制在5000以内:因此,每次更改时,您可能会在堆中分配约30个新单元,但这并不是一个特别大的成本,当然不会像5000那么大

如果
Data.List.sort
不够好,您需要的是:

import Data.List (foldl')
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IM

type Freq = Int
type Count = Int
data Summarizer x = Summ {tracking :: !IntMap [x], least :: !Freq, 
                        size :: !Count, size_of_least :: !Count }

inserting :: x -> Maybe [x] -> Maybe [x]
inserting x Nothing = Just [x]
inserting x (Just xs) = Just (x:xs)

sizeLimit :: Summarizer x -> Summarizer x
sizeLimit skip@(Summ strs f_l tot lst) 
    | tot - lst < 5000 = skip
    | otherwise        = Summ strs' f_l' tot' lst'
        where (discarded, strs') = IM.deleteFindMin strs
              (f_l', new_least) = IM.findMin dps'
              tot' = tot - length discarded
              lst' = length new_least

addEl :: (x, Freq) -> Summarizer x -> Summarizer x
addEl (str, f) skip@(Summ strs f_l tot lst)
    | i < f_l && tot >= 5000 = skip
    | otherwise              = sizeLimit $ Summ strs' f_l' tot' lst'
        where strs' = IM.alter (inserting str) f strs
              tot' = tot + 1
              f_l' = min f_l f
              lst' = case compare f_l f of LT -> lst; EQ -> lst + 1; GT -> 1
导入数据列表(foldl')
导入Data.IntMap.Strict(IntMap)
导入符合条件的Data.IntMap.Strict作为IM
类型Freq=Int
类型计数=Int
数据摘要器x=sum{tracking::!IntMap[x],least::!Freq,
大小::!计数,最小值的大小::!计数}
插入::x->Maybe[x]->Maybe[x]
插入x Nothing=Just[x]
插入x(仅xs)=仅(x:xs)
sizeLimit::摘要器x->摘要器x
sizeLimit skip@(总和)
|tot-lst<5000=跳过
|否则=汇总表'f_l'tot'lst'
其中(已丢弃,strs')=IM.deleteFindMin strs
(f_l',至少新)=IM.findMin dps'
tot'=tot-丢弃的长度
lst'=最小新长度
addEl::(x,Freq)->摘要器x->摘要器x
加法(str,f)跳过@(总和)
|i=5000=跳过
|否则=大小限制$Summ strs'f_l'tot'lst'
其中strs'=IM.alter(插入str)f strs
tot'=tot+1
f_l'=最小f_l f
lst'=LT->lst的案例比较f_l f;等式->lst+1;燃气轮机->1
注意,我们存储字符串列表以处理重复频率;我们通常跳过更新,一个
import Data.List (foldl')
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IM

type Freq = Int
type Count = Int
data Summarizer x = Summ {tracking :: !IntMap [x], least :: !Freq, 
                        size :: !Count, size_of_least :: !Count }

inserting :: x -> Maybe [x] -> Maybe [x]
inserting x Nothing = Just [x]
inserting x (Just xs) = Just (x:xs)

sizeLimit :: Summarizer x -> Summarizer x
sizeLimit skip@(Summ strs f_l tot lst) 
    | tot - lst < 5000 = skip
    | otherwise        = Summ strs' f_l' tot' lst'
        where (discarded, strs') = IM.deleteFindMin strs
              (f_l', new_least) = IM.findMin dps'
              tot' = tot - length discarded
              lst' = length new_least

addEl :: (x, Freq) -> Summarizer x -> Summarizer x
addEl (str, f) skip@(Summ strs f_l tot lst)
    | i < f_l && tot >= 5000 = skip
    | otherwise              = sizeLimit $ Summ strs' f_l' tot' lst'
        where strs' = IM.alter (inserting str) f strs
              tot' = tot + 1
              f_l' = min f_l f
              lst' = case compare f_l f of LT -> lst; EQ -> lst + 1; GT -> 1