从一个文件中读取字符串并添加到另一个带有后缀的文件以使其唯一
Posted
技术标签:
【中文标题】从一个文件中读取字符串并添加到另一个带有后缀的文件以使其唯一【英文标题】:Reading strings from one file and adding to another file with suffix to make unique 【发布时间】:2011-05-19 20:06:59 【问题描述】:我正在用 ruby 处理文档。
我有一个文档,我正在使用正则表达式提取特定字符串,然后将它们添加到另一个文件中。当添加到目标文件时,它们必须是唯一的,所以如果目标文件中已经存在该字符串,我将添加一个简单的后缀,例如<word>_1
。最终我想通过名称来引用字符串,所以随机数生成或从日期开始的字符串是不好的。
目前,我将添加的每个单词存储在一个数组中,然后每次添加一个单词时,我都会检查该字符串是否存在于数组中,如果只有 1 个重复则很好,但可能有 2 个或更多,所以我需要检查初始字符串然后循环递增后缀直到它不存在,(我已经简化了我的代码,所以可能存在错误)
def add_word(word)
if @added_words include? word
suffix = 1
suffixed_word = word
while added_words include? suffixed_word
suffixed_word = word + "_" + suffix.to_s
suffix += 1
end
word = suffixed_word
end
@added_words << word
end
看起来很乱,有没有更好的算法或 ruby 方法来做到这一点?
【问题讨论】:
您希望字符串是唯一的,还是要保留您找到该字符串的次数的直方图?为什么附加 _n 是一个好的解决方案? 我问的原因可能是您的解决方案的架构很差一两层。 如果您将字符串用作某些东西的 id 并且其中有很多,也许将它们放入 sqlite 数据库并给它们实际的 id,然后执行 INSERT OR IGNORE 会是一个更好的解决方案;或者如果它们只有几 Mb,也许只是将它们全部列出到文件中并在最后对文件调用 shell 命令 'uniq' 会更合适。 你可能是对的,它是一个非常基本的工具,可以帮助解决更大的问题,所以我不想过多参与,这是在考虑目标文件的唯一性之后才考虑的。我不想跟踪有多少重复项,但字符串形成了部分的标题,我需要能够引用这些部分 为建议喝彩,数据库的参与增加了太多复杂性,想法是从字符串列表中为配置文件构建一个模板,该列表将存储每个字符串的属性 【参考方案1】:制作@added_words
一个集合(不要忘记require 'set'
)。这使得查找更快,因为集合是用哈希实现的,同时仍然使用include?
来检查集合成员资格。提取最高使用的后缀也很容易:
>> s << 'foo'
#=> #<Set: "foo">
>> s << 'foo_1'
#=> #<Set: "foo", "foo_1">
>> word = 'foo'
#=> "foo"
>> s.max_by |w| w =~ /#word_?(\d+)?/ ; $1 || ''
#=> "foo_1"
>> s << 'foo_12' #=>
#<Set: "foo", "foo_1", "foo_12">
>> s.max_by |w| w =~ /#word_?(\d+)?/ ; $1 || ''
#=> "foo_12"
现在要获得可以插入的下一个值,您只需执行以下操作(假设您已经有 12 个foo
s,所以下一个应该是foo_13
):
>> s << s.max_by |w| w =~ /#word_?(\d+)?/ ; $1 || '' .next
#=> #<Set: "foo", "foo_1", "foo_12", "foo_13"
对不起,如果这些例子有点混乱,我今天早些时候麻醉了。不过,这应该足以让您了解集合如何可能对您有所帮助(其中大部分也可以与数组一起使用,但集合的查找速度更快)。
【讨论】:
+1 顺便在麻醉的影响下回答SOF 呵呵,SO瘾在这本里很厉害;-)【参考方案2】:将@added_words 更改为默认为零的哈希值。然后你可以这样做:
@added_words = Hash.new(0)
def add_word( word)
@added_words[word] += 1
end
# put it to work:
list = %w(test foo bar test bar bar)
names = list.map do |w|
"#w_#add_word(w)"
end
p @added_words
#=> "test"=>2, "foo"=>1, "bar"=>3
p names
#=>["test_1", "foo_1", "bar_1", "test_2", "bar_2", "bar_3"]
【讨论】:
【参考方案3】:在这种情况下,我可能会使用集合或哈希:
#in your class:
require 'set'
require 'forwardable'
extend Forwardable #I'm just including this to keep your previous api
#elsewhere you're setting up your instance_var, it's probably [] at the moment
def initialize
@added_words = Set.new
end
#then instead of `def add_word(word); @added_words.add(word); end`:
def_delegator :added_words, :add_word, :add
#or just change whatever loop to use #@added_words.add('word') rather than self#add_word('word')
#@added_words.add('word') does nothing if 'word' already exists in the set.
如果您有一些属性要通过这些部分进行分组,那么哈希可能会更好:
#elsewhere you're setting up your instance_var, it's probably [] at the moment
def initialize
@added_words =
end
def add_word(word, attrs=)
@added_words[word] ||= []
@added_words[word].push(attrs)
end
【讨论】:
【参考方案4】:以“错误的方式”做,但代码稍微好一点:
def add_word(word)
if @added_words.include? word
suffixed_word = 1.upto(1.0/0.0) do |suffix|
candidate = [word, suffix].join("_")
break candidate unless @added_words.include?(candidate)
end
word = suffixed_word
end
@added_words << word
end
【讨论】:
以上是关于从一个文件中读取字符串并添加到另一个带有后缀的文件以使其唯一的主要内容,如果未能解决你的问题,请参考以下文章
使用java的输入输出流将一个文本文件的内容按行读取,每读一行就顺序添加行号,并写入到另一个文件中
使用带有 Node.js 的 AWS Lambda 函数从 S3 存储桶中提取 zip 文件并上传到另一个存储桶