-
Notifications
You must be signed in to change notification settings - Fork 2
/
extArray.rb
194 lines (167 loc) · 3.76 KB
/
extArray.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# extensions to the Array class
require 'extMath'
class Array
def shuffle
sort_by { rand }
end
def shuffle!
self.replace shuffle
end
#returns an array containing any duplicated items in the array
def dups
inject({}) {|h,v| h[v]=h[v].to_i+1; h}.reject{|k,v| v==1}.keys
end
#-------------------
# mathy functions
def product(other)
inject([]) do |ret, es|
ret += other.map{|eo| [es, eo]}
end
end
# sums any array by converting elements to floats
# use with caution on non-float arrays
def sum
sum = 0
self.each{|i|
sum += i.to_f
}
return sum
end
# assumes that the array is already composed of an Enumerable type
# faster than above method
def sumNum
sum = 0
self.each{|i|
sum += i
}
return sum
end
def avg
return self.sum/self.length
end
def mean
return self.sum/self.length
end
def median
#quick sanity check - do we have numbers?
if self[0].is_a?(Float) || self[0].is_a?(Integer)
mid = (self.length/2).to_i
return self.sort![mid]
else
raise "median requires an array of integers or floats"
end
end
def variance(sd=false)
n = 0
mean = 0.0
s = 0.0
self.each { |x|
n = n + 1
delta = x - mean
mean = mean + (delta / n)
s = s + delta * (x - mean)
}
# if we are calculating std deviation
# of a sample have to change this
if sd == true
return s / (n-1)
else
return s / n
end
end
# calculate the standard deviation of a population
# accepts: an array, the population
# returns: the standard deviation
def standard_deviation
Math.sqrt(self.variance)
end
def sd
standard_deviation
end
# functions to do combinations (choose n of k)
# usage: choose(array,3)
# returns: array of arrays containing combos
def combinations(num)
return [] if num < 1 || num > size
return map{|e| [e] } if num == 1
tmp = self.dup
self[0, size - (num - 1)].inject([]) do |ret, e|
tmp.shift
ret += tmp.combination(num - 1).map{|a| a.unshift(e) }
end
end
#alias for above
def choose(k)
return self.combination(k)
end
# returns all permutations - use with caution on
# huge arrays
def perm(n = size)
if size < n or n < 0
elsif n == 0
yield([])
else
self[1..-1].perm(n - 1) do |x|
(0...n).each do |i|
yield(x[0...i] + [first] + x[i..-1])
end
end
self[1..-1].perm(n) do |x|
yield(x)
end
end
end
# in a binary Array, flip all values from true to false, or vice-versa
# (probably should be abstracted to a binaryArray class)
def flipBits
temp = self.collect{|x|
if x == true
x = false
elsif x == false
x = true
else
raise "flipBits can only be used on binary arrays (all values are true/false)"
end
}
return temp
end
def flipBits!
self.collect!{|x|
if x == true
x = false
elsif x == false
x = true
else
raise "flipBits can only be used on binary arrays (all values are true/false)"
end
}
end
#convert all values to floats
def to_f
self.collect!{|x| x.to_f}
end
#does what it says on the box
def calcUniqPermutations
counts = Hash.new(0)
self.each{|item| counts[item]+=1}
product = 1
counts.each{|k,v|
if v > 1
product *= Math.factorial(v)
end
}
return Math.factorial(self.length)/product
end
#the same, but in log2 space
def calcUniqPermutationsLog2
counts = Hash.new(0)
self.each{|item| counts[item]+=1}
sum = 0
counts.each{|k,v|
if v > 1
sum += Math.log2factorial(v)
end
}
return Math.log2factorial(self.length) - sum
end
end