2

假设我有一个正在用 Ruby 处理的染色体数据文件,

#Base_ID    Segment_ID      Read_Depth  
1                           100            
2                           800         
3           seg1            1900            
4           seg1            2700           
5                           1600            
6                           2400            
7                           200
8                           15000
9           seg2            300
10          seg2            400
11          seg2            900
12                          1000
13                          600
... 

我将每一行粘贴到数组的哈希中,我的键取自第 2 列 Segment_ID,我的值取自第 3 列 Read_Depth,给了我

mr_hashy = { 
  "seg1"  => [1900, 2700],
  ""      => [100, 800, 1600, 2400, 200, 15000, 1000, 600],
  "seg2"  => [300, 400, 900],
}

引物是由上述数据中的两个连续行组成的小段,位于每个常规段之前和之后。常规段的 Segment_ID 具有非空字符串值,并且长度不同,而第二列中具有空字符串的行是引物的一部分。引物片段的长度始终相同,为 2。如上所示,Base_ID 的 1、2、5、6、7、8、12、13 是引物的一部分。总共有四个引物片段存在于上述数据中。

我想做的是,在第 2 列 Segment_ID 中遇到带有空字符串的行时,将 READ_DEPTH 添加到我的哈希中的适当元素中。例如,我从上面想要的结果看起来像

mr_hashy = {
  "seg1"   => [100, 800, 1900, 2700, 1600, 2400],
  "seg2"   => [200, 15000, 300, 400, 900, 1000, 600],
}
4

3 回答 3

3
hash = Hash.new{|h,k| h[k]=[] }

# Throw away the first (header) row
rows = DATA.read.scan(/.+/)[1..-1].map do |row|
  # Throw away the first (entire row) match
  row.match(/(\d+)\s+(\w+)?\s+(\d+)/).to_a[1..-1]
end

last_segment       = nil
last_valid_segment = nil
rows.each do |base,segment,depth|
  if segment && !last_segment
    # Put the last two values onto the front of this segment
    hash[segment].unshift( *hash[nil][-2..-1] )
    # Put the first two values onto the end of the last segment
    hash[last_valid_segment].concat(hash[nil][0,2]) if last_valid_segment
    hash[nil] = []
  end
  hash[segment] << depth
  last_segment = segment
  last_valid_segment = segment if segment
end
# Put the first two values onto the end of the last segment
hash[last_valid_segment].concat(hash[nil][0,2]) if last_valid_segment
hash.delete(nil)

require 'pp'
pp hash
#=> {"seg1"=>["100", "800", "1900", "2700", "1600", "2400"],
#=>  "seg2"=>["200", "15000", "300", "400", "900", "1000", "600"]}

__END__
#Base_ID    Segment_ID      Read_Depth  
1                           100            
2                           800         
3           seg1            1900            
4           seg1            2700           
5                           1600            
6                           2400            
7                           200
8                           15000
9           seg2            300
10          seg2            400
11          seg2            900
12                          1000
13                          600
于 2011-01-03T23:20:22.910 回答
2

二次重构。我认为这是干净、优雅的,最重要的是完整的。它很容易阅读,没有硬编码的字段长度或丑陋的 RegEx。我投票给我的最好的!耶!我是最棒的,耶!;)

def parse_chromo(file_name)

  last_segment = ""
  segments = Hash.new {|segments, key| segments[key] = []}

  IO.foreach(file_name) do |line|
    next if !line || line[0] == "#"

    values = line.split
    if values.length == 3 && last_segment != (segment_id = values[1])
      segments[segment_id] += segments[last_segment].pop(2)
      last_segment = segment_id
    end

    segments[last_segment] << values.last
  end

  segments.delete("")
  segments
end

puts parse_chromo("./chromo.data")

我用它作为我的数据文件:

#Base_ID    Segment_ID      Read_Depth  
1                           101            
2                           102            
3           seg1            103            
4           seg1            104           
5                           105            
6                           106            
7                           201
8                           202
9           seg2            203
10          seg2            204            
11                          205            
12                          206
13                          207
14                          208            
15                          209            
16                          210
17                          211
18                          212
19                          301
20                          302
21         seg3             303
21         seg3             304
21                          305
21                          306
21                          307

哪个输出:

{
  "seg1"=>["101", "102", "103", "104", "105", "106"], 
  "seg2"=>["201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212"], 
  "seg3"=>["301", "302", "303", "304", "305", "306", "307"]
}
于 2011-01-03T23:15:01.760 回答
1

这是一些 Ruby 代码(很好的实践示例:P)。我假设列是固定宽度的,您的输入数据似乎就是这种情况。代码会跟踪哪些深度值是引物值,直到找到其中的 4 个,之后它将知道段 id。

require 'pp'
mr_hashy = {}
primer_segment = nil
primer_values = []
while true
  line = gets
  if not line
    break
  end
  base, segment, depth = line[0..11].rstrip, line[12..27].rstrip, line[28..-1].rstrip
  primer_values.push(depth)
  if segment.chomp == ''
    if primer_values.length == 6
      for value in primer_values
        (mr_hashy[primer_segment] ||= []).push(value)
      end
      primer_values = []
      primer_segment = nil
    end
  else
    primer_segment = segment
  end
end
PP::pp(mr_hashy)

提供的输入输出:

{"seg1"=>["100", "800", "1900", "2700", "1600", "2400"],
 "seg2"=>["200", "15000", "300", "400", "900", "1000"]}
于 2011-01-03T22:54:23.470 回答