shuffle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +1 -0
  3. data/lib/shuffle.rb +103 -0
  4. metadata +64 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Evan Senter
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1 @@
1
+ http://www.youtube.com/watch?v=xFZYJIwfUbo
data/lib/shuffle.rb ADDED
@@ -0,0 +1,103 @@
1
+ require "rand"
2
+
3
+ class Shuffle
4
+ PREFIXES = {
5
+ "mono" => 1,
6
+ "di" => 2,
7
+ "tri" => 3,
8
+ "quad" => 4
9
+ }
10
+
11
+ attr_reader :sequence, :rejoin
12
+
13
+ def initialize(sequence)
14
+ @sequence = if sequence.is_a?(String) && sequence !~ /\s/
15
+ @rejoin = true
16
+ sequence.split(//)
17
+ else
18
+ sequence
19
+ end
20
+ end
21
+
22
+ def shuffle(size)
23
+ shuffled_sequence = shuffler(size)
24
+
25
+ rejoin ? shuffled_sequence.join : shuffled_sequence
26
+ end
27
+
28
+ def validate(size)
29
+ frequency(sequence.each_cons(size)) == frequency(shuffler(size).each_cons(size))
30
+ end
31
+
32
+ private
33
+
34
+ def shuffler(size)
35
+ if size == 1
36
+ sequence.shuffle
37
+ else
38
+ edge_hash = shuffle!(edge_list(size))
39
+ shuffle!(edge_hash) until connected?(last_edge_graph(edge_hash, size), size)
40
+ construct_from(edge_hash, size)
41
+ end
42
+ end
43
+
44
+ def start(size)
45
+ sequence[0, size - 1]
46
+ end
47
+
48
+ def terminal(size)
49
+ sequence[(-(size - 1))..-1]
50
+ end
51
+
52
+ def edge_list(size)
53
+ sequence.each_cons(size).inject(Hash.new { |hash, key| hash[key] = [] }) do |hash, subsequence|
54
+ hash.tap { hash[subsequence[0..-2]] << subsequence }
55
+ end
56
+ end
57
+
58
+ def shuffle!(edge_hash)
59
+ edge_hash.tap { edge_hash.values.map(&:shuffle!) }
60
+ end
61
+
62
+ def last_edge_graph(edge_hash, size)
63
+ edge_hash.reject { |token, edges| token == terminal(size) }.values.map(&:last)
64
+ end
65
+
66
+ def connected?(edges, size)
67
+ terminal = terminal(size)
68
+ vertex_terminates = edges.map { |edge| edge[0..-2] }.inject({}) { |hash, v| hash.tap { hash[v] = false } }
69
+ queue = edges.select { |edge| edge[1..-1] == terminal }
70
+
71
+ until queue.empty?
72
+ edge = queue.pop
73
+
74
+ if vertex_terminates[edge[0..-2]] = vertex_terminates[edge[1..-1]] || edge[1..-1] == terminal
75
+ queue.push(*edges.select { |queueable_edge| queueable_edge[1..-1] == edge[0..-2] })
76
+ end
77
+ end
78
+
79
+ vertex_terminates.values.all?
80
+ end
81
+
82
+ def construct_from(edge_hash, size)
83
+ shuffled_sequence = edge_hash[start(size)].shift
84
+
85
+ until edge_hash.values.flatten.empty?
86
+ shuffled_sequence.concat(edge_hash[shuffled_sequence[-(size - 1)..-1]].shift[-1, 1])
87
+ end
88
+
89
+ shuffled_sequence
90
+ end
91
+
92
+ def frequency(array)
93
+ array.inject(Hash.new { |hash, key| hash[key] = 0 }) { |hash, token| hash.tap { hash[token] += 1 } }
94
+ end
95
+
96
+ def method_missing(name, *args, &block)
97
+ if size = PREFIXES[name.to_s.match(/^(\w+)shuffle$/)[1]]
98
+ shuffle(size.to_i)
99
+ else
100
+ super
101
+ end
102
+ end
103
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shuffle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Evan Senter
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rand
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.1
30
+ description: Simple method to shuffle list while preserving n-mer frequency.
31
+ email: evansenter@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - lib/shuffle.rb
37
+ - LICENSE
38
+ - README.md
39
+ homepage: http://rubygems.org/gems/shuffle
40
+ licenses: []
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 1.8.24
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: n-mer shuffling.
63
+ test_files: []
64
+ has_rdoc: