Related
I'm attempting to return a count of the total number of matching and non-matching entries in a set of two ranges.
I'm trying to avoid looping over the array twice like this:
#expected output:
#inside: 421 | outside: 55
constant_range = 240..960
sample_range = 540..1015
sample_range_a = sample_range.to_a
def generate_range
inside = sample_range_a.select { |val| constant_range.include?(val) }.count
outside = sample_range_a.select { |val| !constant_range.include?(val) }.count
end
# I was thinking of a counter, but thought that would be even more ineffective
def generate_range
a = 0
b = 0
sample_range_a.select { |val| constant_range.include?(val) ? a++ : b++ }
end
I don't know if this is entirely your case, but if they're always number ranges with an interval of 1 and not any arbitrary array, the solution can be optimized to O(1), unlike the other methods using to_a that are at least O(n). In other words, if you have a BIG range, those array solutions would choke badly.
Assuming that you'll always use an ascending range of numbers with interval of 1, it means you can count them just by using size (count would be our enemy in this situation).
With that said, using simple math you can first check if the ranges may intersect, if not, just return 0. Otherwise, you can finally calculate the new range interval and get its size.
def range_intersection_count(x, y)
return 0 if x.last < y.first || y.last < x.first
([x.begin, y.begin].max..[x.max, y.max].min).size
end
This will count the number of elements that intersect in two ranges in O(1). You can test this code with something like
range_intersection_count(5000000..10000000000, 3000..1000000000000)
and then try the same input with the other methods and watch your program hang.
The final solution would look something like this:
constant_range = (240..960)
sample_range = (540..1015)
inside_count = range_intersection_count(constant_range, sample_range) # = 421
outside_count = sample_range.size - inside_count # = 55
constant_range = (240..960).to_a
sample_range = (540..1015).to_a
inside_count = (sample_range & constant_range).count #inside: 421
outside_count = sample_range.count - inside_count #outside: 55
You can use - (difference) in Ruby:
constant_range = (240..960).to_a
sample_range = (540..1015).to_a
puts (sample_range - constant_range).count # 55
I would like to get random 3 numbers (e.g. 3, 177, 244) from an array of 0 to 250 in every event, and excluding a pre-defined number between 0 and 250 (e.g 220).
For example,
In the 1st event (push button),
I got 220 from another data set, so I need random numbers like a=3, b=177, c=244 (a, b, c should not be 220).
In the 2nd event (push button),
I got 15 from another data set,, so I need random numbers like a=77, b=109, c=166 (a, b, c should not be 15)
Do you have any good idea to implement this?
Looking for a good mathematician! Cheers.
Based on #Evan Wrynn, I tried the following, but I need one more step to get random 3 numbers in a table, right. Basically I try to put all numbers in t. d is a variable I got from another source. The outcome should be t which contains 3 random numbers (i.e. t={4, 88, 221} (except 85 in this case)). Currently t seems to get duplicate numbers :(. Completely alternative idea is also welcome.
d = 85
dt = {}
t = {}
table.insert(dt,d)
while table.getn(t) < 3 do
function GetMathRandomExclude(lowerbound,upperbound,exclude)
local x = math.random(lowerbound,upperbound)
for _,v in pairs(exclude) do
if v == x then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
else
return table.insert(t,x)
end
end
end
GetMathRandomExclude(1,250,dt)
end
for i, v in ipairs(t) do
print(i, v)
end
function GetMathRandomExclude(lowerbound,upperbound,exclude)
local x = math.random(lowerbound,upperbound)
for _,v in pairs(exclude) do
if v == x then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
end
end
return x
end
d = 62
dt = {}
t = {}
table.insert(dt,d)
while table.getn(t) < 3 do
local randomnum = GetMathRandomExclude(1,250,dt)
table.insert(t,randomnum)
table.insert(dt,randomnum)
end
for i, v in ipairs(t) do
print(i, v)
end
The first problem you had was the random function, it would check only the first number as you returned after the if statement. This is sorted by putting it at the end of the function.
you can remove table.insert(dt,randomnum) if you don't want the numbers picked not to be added to the exclusion
function GetMathRandomExclude(lowerbound,upperbound,exclude)
local x = math.random(lowerbound,upperbound)
if x == exclude then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
end
return x
end
print(GetMathRandomExclude(1,3,2)) -> (when called 10 times I got "3" 7 times and "1" 3 times.
If the number = the number to exclude it than recalls the function.
You can check with a table to make it have multiple exclusions.
EDIT:
function GetMathRandomExclude(lowerbound,upperbound,exclude)
local x = math.random(lowerbound,upperbound)
if type(exclude) == "table" then
for _,v in pairs(exclude) do
if v == x then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
end
end
else
if x == exclude then
return GetMathRandomExclude(lowerbound,upperbound,exclude)
end
end
return x
end
print(GetMathRandomExclude(1,100,{85,62})) -> 40
GetMathRandomExclude(NUMBER lowerbound, NUMBER upperbound, NUMBER OR TABLE exclude)
in answers above we roll random number, and if it should be excluded, we roll another random number until we get one that should not be excluded. Drawback is if size of "ok" set and "exclude" set are comparable, we may reroll often.
i propose another approach, which i'll describe in example: we want random from 1 to 10 excluding 5. So we roll random from 1 to 9, and if our result is >4 then we add 1 to result. So we get random from 1 to 10 excluding 5. It can be implemented in following way:
local function get_random_n(min, max , exclude, n)
local result = {}
for i = 1, n do
table.sort(exclude)
result[i] = math.random(min, max - #exclude)
for j = 1, #exclude do
if result[i] > (exclude[j]-1) then
result[i]=result[i]+1
end
end
exclude[#exclude+1]=result[i]
end
return result
end
local function test()
for j = 1, 10 do
local x = get_random_n(1, 10, {3,5,7}, 7)
print("========")
for k = 1, #x do
print(x[k])
end
end
end
If you want to create NxM matrix in Lua you basically do the following:
function get_zero_matrix(rows, cols)
matrix = {}
for i=1, rows do
matrix[i] = {}
for j=1, cols do
matrix[i][j] = 0
end
end
return matrix
end
However, on the official Lua website I've seen the second variant:
function get_zero_matrix2(rows, cols)
mt = {}
for i=1, rows do
for j=1, cols do
mt[i*cols + j] = 0
end
end
return mt
end
First, I don't understand how it works. How [i*M + j] index is supposed to create rows and columns?
Second, I tried this variant, it works but what it returns is actually an array, not NxM matrix:
M = function get_zero_matrix2(10, 20)
print(#M, #M[1])
> attempt to get length of a nil value (field '?')
Can you please explain how the second variant works?
Maybe I am misinterpreting it.
I don't understand how it works.
For a 2D array of dimension N (rows) x M (cols), the total number of required elements = N * M. Now creating N * M elements in one shot as a single array, we will essentially have a 1D array (flattened 2D array) in memory. Since the formula assumes array index start as 0 and not 1 (the usual Lua's convention), we'll follow 0: the first M items with indices [0, M - 1] form row 0, next M items with indices [M, 2M - 1] form row 1, and so on.
Memory layout for a 5 x 2 array; index 4 in this 1D array is (2, 0) in the 2D array.
--+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--
... | 0,0 | 0,1 | 1,0 | 1,1 | 2,0 | 2,1 | 3,0 | 3,1 | 4,0 | 4,1 | ...
--+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--
|-- row 0 --|-- row 1 --|-- row 2 --|-- row 3 --|-- row 4 --|
To access element (i, j), one would get past i - 1 rows and then access the jth item on the ith row. But the index is already one lesser, since the index starts at 0, so i can be used as-is. Thus i * rows + j gives the right index.
How [i*M + j] index is supposed to create rows and columns?
It doesn't. It's an abstraction over a 1D array of numbers, giving the interface of a matrix. In languages like C, declaring a 2D array, most implementations do something similar. int a[2][3] would create an array of 6 integers and do the indexing with the formula above, so this is not an uncommon pattern.
The variant available on Lua PiL is actually representation/mapping of a 2D array as a 1D array.
Basically, consider the following 2x3 array/matrix:
{
{11, 12, 13},
{21, 22, 23}
}
The variant, instead creates it as:
{
[4] = 11,
[5] = 12,
.
.
.
[9] = 23
}
Now, when you want to, let's say, get matrix[1][x], you'll instead fetch:
matrix[1 * rows + x]
It does not, in any way create rows and columns. It is just data stored in a single row of numbers. You will have to implement your own logic; which here, essentially; is i * M + j.
The i*M + j is usually seen in languages with 0-indexing array, like C, where the matrix would be:
{
[0] = 11,
[1] = 12,
[2] = 13,
.
.
.
[5] = 23
}
I'm trying to make a function that generate random number, but never twice.
Here is what I got so far, but it doesn't work. It compiles, but then again it insert multiple times the same number in my array.
quiz = 10
array = {}
array[1] = 0 -- just to have something in it because it won't work in my loop otherwise...
ok = false
repeat
rdm = math.ceil(math.random() * quiz)
for i = 0, #array do
if(rdm == array[i]) then
break -- to break the for loop to pick a new number
elseif(rdm ~= array[i]) then
ok = true -- to end the repeat loop
table.insert(array, rdm) -- to keep a track of what I got so far
end
end
until ok == true
for b = 0, #array do -- #array should be ten
print(array[b])
end
What it does is it generate multiple times the same number and says it's different from the one in the table...
I guess my problem comes from logic... but I don't know where cause it all make sense for me
If you know you are going to need at most N numbers, you could pregenerate the random numbers and insert them in a table according to their value. Then your function randomly picks a number from that table and removes the number. Something like:
local rands = {}
local numRands = 100
-- populate table of random numbers
while #rands < numRands do
local r = math.random(1,1000)
rands[r]=r -- if duplicate, table stays same
end
local function getNeverSameRandom()
local index = math.random(1,numRands)
return table.remove(rands, index)
end
If you don't know how many to populate, then keep track via table:
local randsUsed = {}
local maxRand = 1000000 -- largest random # you want
local function getNeverSameRandom()
local rnd
repeat
rnd = math.random(1,maxRand)
until randsUsed[rnd] == nil
randsUsed[rnd] = rnd
return rnd
end
The problem of course is that if you call getNeverSameRandom many times, like half the max random number, your randsUsed table is going to get quite full, and the repeat-until is going to take longer and longer. Eventually, the table will be full, and the function will be in an infinite loop. You could easily check by keeping track with a counter, but you cannot use #randsUsed because randsUsed is a table with "holes" so the # operation can't be used. For example:
local randsUsedCount = 0
local function getNeverSameRandom()
if randsUsedCount == maxRand then
error("No more random #'s left in range 1-"..maxRand)
end
local rnd
repeat
rnd = math.random(1,maxRand)
until randsUsed[rnd] == nil
randsUsed[rnd] = rnd
randsUsedCount = randsUsedCount + 1
return rnd
end
The simplest way is to probably prepopulate an array of elements with the sequence you need (for example, 1..1000) and then shuffle the elements in place using something like Fisher-Yates algorithm:
local rands, n = {}, 1000
-- prepopulate
for i = 1, n do rands[i] = i end
-- shuffle
for i = n, 2, -1 do
local j = math.random(i)
rands[j], rands[i] = rands[i], rands[j]
end
-- use
print(table.remove(rands))
The same page also has "inside-out" version of the algorithm that does both initialization and shuffling.
I'm trying to write a piece of code that will do the following:
Take the numbers 0 to 9 and assign one or more letters to this number. For example:
0 = N,
1 = L,
2 = T,
3 = D,
4 = R,
5 = V or F,
6 = B or P,
7 = Z,
8 = H or CH or J,
9 = G
When I have a code like 0123, it's an easy job to encode it. It will obviously make up the code NLTD. When a number like 5,6 or 8 is introduced, things get different. A number like 051 would result in more than one possibility:
NVL and NFL
It should be obvious that this gets even "worse" with longer numbers that include several digits like 5,6 or 8.
Being pretty bad at mathematics, I have not yet been able to come up with a decent solution that will allow me to feed the program a bunch of numbers and have it spit out all the possible letter combinations. So I'd love some help with it, 'cause I can't seem to figure it out. Dug up some information about permutations and combinations, but no luck.
Thanks for any suggestions/clues. The language I need to write the code in is PHP, but any general hints would be highly appreciated.
Update:
Some more background: (and thanks a lot for the quick responses!)
The idea behind my question is to build a script that will help people to easily convert numbers they want to remember to words that are far more easily remembered. This is sometimes referred to as "pseudo-numerology".
I want the script to give me all the possible combinations that are then held against a database of stripped words. These stripped words just come from a dictionary and have all the letters I mentioned in my question stripped out of them. That way, the number to be encoded can usually easily be related to a one or more database records. And when that happens, you end up with a list of words that you can use to remember the number you wanted to remember.
It can be done easily recursively.
The idea is that to handle the whole code of size n, you must handle first the n - 1 digits.
Once you have all answers for n-1 digits, the answers for the whole are deduced by appending to them the correct(s) char(s) for the last one.
There's actually a much better solution than enumerating all the possible translations of a number and looking them up: Simply do the reverse computation on every word in your dictionary, and store the string of digits in another field. So if your mapping is:
0 = N,
1 = L,
2 = T,
3 = D,
4 = R,
5 = V or F,
6 = B or P,
7 = Z,
8 = H or CH or J,
9 = G
your reverse mapping is:
N = 0,
L = 1,
T = 2,
D = 3,
R = 4,
V = 5,
F = 5,
B = 6,
P = 6,
Z = 7,
H = 8,
J = 8,
G = 9
Note there's no mapping for 'ch', because the 'c' will be dropped, and the 'h' will be converted to 8 anyway.
Then, all you have to do is iterate through each letter in the dictionary word, output the appropriate digit if there's a match, and do nothing if there isn't.
Store all the generated digit strings as another field in the database. When you want to look something up, just perform a simple query for the number entered, instead of having to do tens (or hundreds, or thousands) of lookups of potential words.
The general structure you want to hold your number -> letter assignments is an array or arrays, similar to:
// 0 = N, 1 = L, 2 = T, 3 = D, 4 = R, 5 = V or F, 6 = B or P, 7 = Z,
// 8 = H or CH or J, 9 = G
$numberMap = new Array (
0 => new Array("N"),
1 => new Array("L"),
2 => new Array("T"),
3 => new Array("D"),
4 => new Array("R"),
5 => new Array("V", "F"),
6 => new Array("B", "P"),
7 => new Array("Z"),
8 => new Array("H", "CH", "J"),
9 => new Array("G"),
);
Then, a bit of recursive logic gives us a function similar to:
function GetEncoding($number) {
$ret = new Array();
for ($i = 0; $i < strlen($number); $i++) {
// We're just translating here, nothing special.
// $var + 0 is a cheap way of forcing a variable to be numeric
$ret[] = $numberMap[$number[$i]+0];
}
}
function PrintEncoding($enc, $string = "") {
// If we're at the end of the line, then print!
if (count($enc) === 0) {
print $string."\n";
return;
}
// Otherwise, soldier on through the possible values.
// Grab the next 'letter' and cycle through the possibilities for it.
foreach ($enc[0] as $letter) {
// And call this function again with it!
PrintEncoding(array_slice($enc, 1), $string.$letter);
}
}
Three cheers for recursion! This would be used via:
PrintEncoding(GetEncoding("052384"));
And if you really want it as an array, play with output buffering and explode using "\n" as your split string.
This kind of problem are usually resolved with recursion. In ruby, one (quick and dirty) solution would be
#values = Hash.new([])
#values["0"] = ["N"]
#values["1"] = ["L"]
#values["2"] = ["T"]
#values["3"] = ["D"]
#values["4"] = ["R"]
#values["5"] = ["V","F"]
#values["6"] = ["B","P"]
#values["7"] = ["Z"]
#values["8"] = ["H","CH","J"]
#values["9"] = ["G"]
def find_valid_combinations(buffer,number)
first_char = number.shift
#values[first_char].each do |key|
if(number.length == 0) then
puts buffer + key
else
find_valid_combinations(buffer + key,number.dup)
end
end
end
find_valid_combinations("",ARGV[0].split(""))
And if you run this from the command line you will get:
$ ruby r.rb 051
NVL
NFL
This is related to brute-force search and backtracking
Here is a recursive solution in Python.
#!/usr/bin/env/python
import sys
ENCODING = {'0':['N'],
'1':['L'],
'2':['T'],
'3':['D'],
'4':['R'],
'5':['V', 'F'],
'6':['B', 'P'],
'7':['Z'],
'8':['H', 'CH', 'J'],
'9':['G']
}
def decode(str):
if len(str) == 0:
return ''
elif len(str) == 1:
return ENCODING[str]
else:
result = []
for prefix in ENCODING[str[0]]:
result.extend([prefix + suffix for suffix in decode(str[1:])])
return result
if __name__ == '__main__':
print decode(sys.argv[1])
Example output:
$ ./demo 1
['L']
$ ./demo 051
['NVL', 'NFL']
$ ./demo 0518
['NVLH', 'NVLCH', 'NVLJ', 'NFLH', 'NFLCH', 'NFLJ']
Could you do the following:
Create a results array.
Create an item in the array with value ""
Loop through the numbers, say 051 analyzing each one individually.
Each time a 1 to 1 match between a number is found add the correct value to all items in the results array.
So "" becomes N.
Each time a 1 to many match is found, add new rows to the results array with one option, and update the existing results with the other option.
So N becomes NV and a new item is created NF
Then the last number is a 1 to 1 match so the items in the results array become
NVL and NFL
To produce the results loop through the results array, printing them, or whatever.
Let pn be a list of all possible letter combinations of a given number string s up to the nth digit.
Then, the following algorithm will generate pn+1:
digit = s[n+1];
foreach(letter l that digit maps to)
{
foreach(entry e in p(n))
{
newEntry = append l to e;
add newEntry to p(n+1);
}
}
The first iteration is somewhat of a special case, since p-1 is undefined. You can simply initialize p0 as the list of all possible characters for the first character.
So, your 051 example:
Iteration 0:
p(0) = {N}
Iteration 1:
digit = 5
foreach({V, F})
{
foreach(p(0) = {N})
{
newEntry = N + V or N + F
p(1) = {NV, NF}
}
}
Iteration 2:
digit = 1
foreach({L})
{
foreach(p(1) = {NV, NF})
{
newEntry = NV + L or NF + L
p(2) = {NVL, NFL}
}
}
The form you want is probably something like:
function combinations( $str ){
$l = len( $str );
$results = array( );
if ($l == 0) { return $results; }
if ($l == 1)
{
foreach( $codes[ $str[0] ] as $code )
{
$results[] = $code;
}
return $results;
}
$cur = $str[0];
$combs = combinations( substr( $str, 1, $l ) );
foreach ($codes[ $cur ] as $code)
{
foreach ($combs as $comb)
{
$results[] = $code.$comb;
}
}
return $results;}
This is ugly, pidgin-php so please verify it first. The basic idea is to generate every combination of the string from [1..n] and then prepend to the front of all those combinations each possible code for str[0]. Bear in mind that in the worst case this will have performance exponential in the length of your string, because that much ambiguity is actually present in your coding scheme.
The trick is not only to generate all possible letter combinations that match a given number, but to select the letter sequence that is most easy to remember. A suggestion would be to run the soundex algorithm on each of the sequence and try to match against an English language dictionary such as Wordnet to find the most 'real-word-sounding' sequences.