Related
I have a ruby array:
["A", "C", "B", "D", "F", "E"]
User will supply an input, e.g.
input = "B"
I want to shift the values in the array, so the first item of the array equals input, and get the result of a new array:
["B", "D", "F", "E", "A", "C"]
User will be choosing from a dropdown options, so they can only choose the letters from original array.
You can use Array#rotate.
arr = ["A", "C", "B", "D", "F", "E"]
arr.rotate(arr.index('B'))
#=> ["B", "D", "F", "E", "A", "C"]
a=b&c=d&e=f&g=h
How to extract this into [a,b,c,d,e,f,g,h]
I know I can use split, but it looks like it can only use only one delimit.
or how to convert into a hash?
split FTW (i.e. the most straightforward, simple way of doing this is):
irb(main):001:0> s = "a=b&c=d&e=f&g=h"
=> "a=b&c=d&e=f&g=h"
irb(main):002:0> s.split(/[=&]/)
=> ["a", "b", "c", "d", "e", "f", "g", "h"]
Other interesting ways of abusing Ruby:
irb(main):001:0> s = "a=b&c=d&e=f&g=h"
=> "a=b&c=d&e=f&g=h"
irb(main):002:0> s.split('=').collect{|x| x.split('&')}.flatten
=> ["a", "b", "c", "d", "e", "f", "g", "h"]
irb(main):003:0> ['=','&'].inject(s) {|t, n| t.split(n).join()}.split('')
=> ["a", "b", "c", "d", "e", "f", "g", "h"]
Also check Cary's and GamesBrainiac's answers for more alternatives :)
You can make a hash very easily with something like this:
myHash = {}
strSplit = "a=b&c=d&e=f&g=h".split("&")
for pair in strSplit
keyValueSplit = pair.split("=")
myHash[keyValueSplit[0]] = keyValueSplit[1]
end
myHash will look like this in the end {"a"=>"b", "c"=>"d", "e"=>"f", "g"=>"h"}
#Mirea's answer is best, but here's another:
s = "a=b&c=d&e=f&g=h"
s.scan /[a-z]/
#=> ["a", "b", "c", "d", "e", "f", "g", "h"]
The regex could of course be adjusted as required. For example:
"123a=b&c=d&E=f&g=h".scan /[A-Za-z0-9]/
#=> ["1", "2", "3", "a", "b", "c", "d", "E", "f", "g", "h"]
or
"1-2-3a=$b&c=d&e=f&g=h".scan /[^=&]/
#=> ["1", "-", "2", "-", "3", "a", "$", "b", "c", "d", "e", "f", "g", "h"]
and so on.
If strings of characters are desired just append + to the character class:
"123a=b&ccc=d&E=f&gg=h".scan /[A-Za-z0-9]+/
#=> ["123a", "b", "ccc", "d", "E", "f", "gg", "h"]
If the string has the alternating form shown in the example, these work as well:
(0..s.size).step(2).map { |i| s[i] }
#=> ["a", "b", "c", "d", "e", "f", "g", "h"]
s.each_char.each_slice(2).map(&:first)
#=> ["a", "b", "c", "d", "e", "f", "g", "h"]
I would use is gsub.
irb(main):001:0> s = "a=b&c=d&e=f&g=h"
=> "a=b&c=d&e=f&g=h"
irb(main):004:0> s.gsub(/[\=\&]/, " ").split()
=> ["a", "b", "c", "d", "e", "f", "g", "h"]
So, what we're doing here is replacing all occurrences of = and & with a single space. We then simply split the string.
I have 5 arrays:
["A", "B", "C"]
["A", "B", "C", "D", "E"]
["A"]
["A", "B", "C", "D", "E", "F"]
["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"]
I would like to create a list of each combination as such:
["AAAAA","AAAAB","AAAAC", "AAAAD"...
"BAAAA","BAAAB","BAAAC", "BAAAD"...]
a = [
["A", "B", "C"],
["A", "B", "C", "D", "E"],
["A"],
["A", "B", "C", "D", "E", "F"],
["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"]
]
a.inject(&:product).map(&:join)
# => ["AAAAA", "AAAAB", "AAAAC", ..., "CEAFM", "CEAFN", "CEAFO"]
Thanks to bluexuemei for the improved answer. The original solution was a.shift.product(*a).map(&:join).
A More Traditional Solution
With such a convenient library, these ruby one-liners seem almost like cheating.
Here is a more traditional way to solve this common problem that can be readily coded into other programming languages:
N = a.reduce(1) { |product,list| product * list.size } # 1350
combinations = []
0.upto(N-1) do |q|
combo = []
a.reverse.each do |list|
q, r = q.divmod list.size
combo << list[r]
end
combinations.push combo.reverse.join
end
combinations
# => ["AAAAA", "AAAAB", "AAAAC", ..., "CEAFM", "CEAFN", "CEAFO"]
The basic idea is to first calculate the total number of combinations N which is just the product of the length of all the lists. Each integer from 0 to N-1 then encodes all the information needed to provide unique indices into each list to produce each combination. One way to think of it is that the index variable q can be expressed as a 5-digit number, where each digit is in a different base, where the base is the size of the corresponding list. That is, the first digit is base-3, the second digit is base-5, the 3rd is base-1 (always 0), the 4th is base-6, and the 5th is base-15. To extract these values from q, this is just taking a series of repeated integer divisions and remainders, as done in the inner loop. Naturally this requires some homework, perhaps looking at simpler examples, to fully digest.
a.reduce(&:product).map(&:join).size
What is a good way to get from this:
['a','b','c',['d1','d2']]
to this:
[['a','b','c','d1']['a','b','c','d2']]
another example, from this:
[['a1','a2'],'b',['c1','c2']]
to this:
[['a1','b','c1'],['a1','b','c2'],['a2','b','c1'],['a2','b','c2']]
edit 1:
Sorry for the confusion and thanks for response so far, the individual contents of the array items doesn't matter but the order must be preserved. The method needs to work for both example because the nested array can be in any position of the outer array, and the nested array can have more the 2 elements.
It's sort of like a regex with multiple or conditions
ab(c|d)
expand to match abc and abd
It is a bit hard to know exactly what you want, but this produces something quite similar:
# Create a list:
a = [['a1','a2'],'b',['c1','c2']]
# Split it into sub-arrays and single values:
list, other = a.partition{|x|x.is_a? Array}
# Split the array in order to get the product:
list_first, list_rest = list.pop, list
# Get the product and add the others_values:
p list_first.product(*list_rest).map{|list| list+other}
#=> [["c1", "a1", "b"], ["c1", "a2", "b"], ["c2", "a1", "b"], ["c2", "a2", "b"]]
1st:
arr1 = ['a','b','c',['d1','d2']]
*a, b = arr1
# ["a", "b", "c", ["d1", "d2"]]
a
# ["a", "b", "c"]
b
# ["d1", "d2"]
b.map{|x| a+[x]}
# [["a", "b", "c", "d1"], ["a", "b", "c", "d2"]]
and 2nd:
a, b, c = [["a1", "a2"], "b", ["c1", "c2"] ]
a.product c
#=> [["a1", "c1"], ["a1", "c2"], ["a2", "c1"], ["a2", "c2"]]
a.product(c).map{|x| x<<b}
#=> [["a1", "c1", "b"], ["a1", "c2", "b"], ["a2", "c1", "b"], ["a2", "c2", "b"]]
#or little less readable:
a.product(c).map{|x| [ x[0], b, x[1] ]}
# [["a1", "b", "c1"], ["a1", "b", "c2"], ["a2", "b", "c1"], ["a2", "b", "c2"]]
hirolau got me really close, here is what I ended with so the order is preserved:
# given a sample list
sample = [['a','b'],'c','d',['e','f'],'g',['h','i']]
# partition out the arrays
arrs, non_arrays = sample.partition {|sample| sample.is_a? Array}
# work out all possible products
first_elem, *the_rest = arrs
products = first_elem.product(*the_rest)
# finally swap it back in to get all valid combinations with order preserved
combinations = []
products.each do |p|
combinations << sample.map {|elem| elem.is_a?(Array) ? p.shift : elem}
end
# combinations
=> [["a", "c", "d", "e", "g", "h"],
["a", "c", "d", "e", "g", "i"],
["a", "c", "d", "f", "g", "h"],
["a", "c", "d", "f", "g", "i"],
["b", "c", "d", "e", "g", "h"],
["b", "c", "d", "e", "g", "i"],
["b", "c", "d", "f", "g", "h"],
["b", "c", "d", "f", "g", "i"]]
randomString.lua
----------------------------------------------------------------------------
-- File: randomString.lua
-- Author: Don Draper
--
-- This is the Lua implementation of my simple 'randomString' function
-- which I previous wrote in PAWN.
----------------------------------------------------------------------------
randomString = {}
local randomCharset = {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
}
function randomString.generate(length)
local currentString = ""
for index = 1, length do
currentString = currentString .. randomCharset[math.random(1, #randomCharset)]
end
return currentString
end
Test.lua
require("randomString")
print(randomString.generate(16))
io.read()
So here is my 'randomString' function which I originally wrote in the PAWN programming language, I thought I would implement it to Lua to generate some password salts. However whenever I call my ported function it always returns the same output whenever I first run the program.
Take this piece of code for example.
for i = 0, 100 do
print(randomString.generate(16))
end
It will always generate the same list of random strings. Can anyone please explain why? Thanks in advance!
math.random generates a sequence of pseudorandom numbers, that is a deterministic sequence that will resemble an actual random sequence. The sequence generated by math.random will be always the same, unless you use math.randomseed.
For every possible value with which you call math.randomseed, math.random will generate a different pseudorandom sequence.
Try this, for example, and you will see a different sequence:
math.randomseed( 7654321 )
for i = 0, 100 do
print(randomString.generate(16))
end
If you want a truly random sequence you should feed randomseed with a true random number before starting the generation.