How to deduplicate an array with substring variations where one substring has precedence over another?
I have a dataset similar to this: http://pastie.org/private/3u1reg72nnjfsgqzgqzwra
开发者_如何学JAVAThe list is a set of filenames that need to be processed. When a filename that has a substring of 10u
exists along with one with a substring of 2u
, the filename with 10u
in it has a subset of data from the file with the 2u
substring. In other words, when you have something like:
20021203_V9ut_2u.txt
20021203_V9ut_10u.txt
or
V9cd_2u.txt
V9cd_10u.txt
the 20021203_V9ut_10u.txt
and V9cd_10u.txt
should be removed from the list and only the filenames with 1u
should remain in the list.
I've attempted a few various methods, but they all feel too much like C or hackish. I have also thought about splitting the string and then building a hash with the values of the 1u
or 10u
and then if a key with a 10u
value in it exists, replace it with 1u
, else discard and then remap the hash to an array for processing the file contents.
What is the "best" or most ruby way to do this and can you provide an example?
If your file list sometimes contains files that don't have a perfect match of 2u and 10u this will help you. It removes the 10u files, if and only if there is a corresponding 2u file, leaves it in the resulting list otherwise.
files = %w(20021203_V9ut_2u.txt
20021203_V9ut_10u.txt
V9cd_2u.txt
V9cd_10u.txt
test1_2u.txt
thing2_10u.txt)
# Reverse sort them if they aren't already that way
files = files.sort {|a,b| b <=> a }
puts files.inspect
scrubbed_files = []
files.each_with_index { |f,i|
scrubbed_files << f unless f =~ /(.*)_10u\.(.*)/ && files[i-1] =~ /#{$1}_2u\.#{$2}/
}
puts scrubbed_files.inspect
Assuming you have an array of all_filenames
as strings:
filenames_2u = all_filenames.reject!{ |f| f =~ /10u/ } # edited to be actual working ruby
edit If the file you provided is what you're working with:
all_filenames = IO.readlines('filenames.txt')
This way is more fun:
a.map {|x| x.split(/_/)}.group_by {|x| x[0...-1]}.map {|_,xx| xx.sort_by {|x| x.last.to_i}.first.join("_")}
That is, split the names into arrays at the underscores, group these by the stems (the parts up to the last underscore), then for each group sort the names by the integer versions of the last bit and take the first one.
This will work for any Xu numbering scheme, so if you had 2u and 5u and 10u you'd get the 2u version, and if you had 10u and 20u you'd get the 10u.
group_by
is cool.
精彩评论