Constructing enums using Z=> with variables instead of list literals - enums

I would like to construct a String-typed enum. The following works:
my Str enum E ( <a b c> Z=> 'one', 'two', 'three' );
E.kv.raku.say;
("c", "three", "a", "one", "b", "two").Seq
However, trying the following does not:
my Str #a = <a b c>;
my Str #b = <one two three>;
my Str enum F ( #a Z=> #b );
F.kv.raku.say;
No values supplied to enum (does #a Z=> #b need to be declared constant?)
Is this not supported?
Raku/roast covers enum construction like in E but I didn't see any test cases for F.
Out of curiosity, I also tried:
my $a = <a b c>;
my $b = <one two three>;
my Str enum G ( $a<> Z=> $b<>.map( { .Str } ) );
G.kv.raku.say;
("", "").Seq

The warning asks:
does #a Z=> #b need to be declared constant
And it's correct; since an enum is a compile-time declaration, everything involved with computing its keys and values must be available at compile time. Declaring #a and #b as constants resolves the problem. Thus:
my constant #a = <a b c>;
my constant #b = <one two three>;
my Str enum F ( #a Z=> #b );
F.kv.raku.say;
Produces:
("a", "one", "c", "three", "b", "two").Seq

Can you let us know what Rakudo version? WithRakudo™ v2022.07 and within the Raku REPL, I see virtually identical returns (i.e. no error):
~$ raku
Welcome to Rakudo™ v2022.07.
Implementing the Raku® Programming Language v6.d.
Built on MoarVM version 2022.07.
To exit type 'exit' or '^D'
[0] > my Str enum E ( <a b c> Z=> 'one', 'two', 'three' );
Map.new((a => one, b => two, c => three))
[1] > E.kv.raku.say;
("a", "one", "c", "three", "b", "two").Seq
[1] > my Str #a = <a b c>;
[a b c]
[2] > my Str #b = <one two three>;
[one two three]
[3] > my Str enum F ( #a Z=> #b );
Map.new((a => one, b => two, c => three))
[4] > F.kv.raku.say;
("b", "two", "a", "one", "c", "three").Seq

Related

What's the difference `{'x'=> 3}` and `{x: 3}`?

I have this:
a = {'x' => 3}
b = {'x': 3}
c = {x: 3}
d = {:x => 3}
e = {:'x' => 3}
So, I have that b = c = d = e = {:x => 3}, meanwhile a = {"x" => 3} but a.class == b.class.
I don't understand what the difference is between a and the rest of variables.
In b,c,d, and e, the key is a Symbol.
In a, the key is a String.
a = { 'x' => 3 } #=> { "x" => 3 }
b = { 'x': 3 } #=> { :x => 3 }
c = { x: 3 } #=> { :x => 3 }
d = { :x => 3 } #=> { :x => 3 }
e = { :'x' => 3 } #=> { :x => 3 }
Your variable a hash has "x" key as a string, while other variables have that key as symbol.
Calling class on an object in Ruby returns its class, in your example it is Hash. In other words, the constructor of all hash instances, such as {x: 3} is Hash object.
There is a significant difference between String and Symbol classes in ruby:
explanation on SO;
good article on the topic.
By convention, all but the very first hash notations cast keys to the Symbol instance, while the first one uses the key (String instance in this particular case) as is. (To be more precise: b and c cast key to the Symbol instance, d and e do not cast anything, but keys given in these cases are Symbol instances already.)
Since ('x' == :x) == false, a hash differs from the latters.

How to write a function to change the value of a variable in the main scope in Ruby

I have a assigment to write a value swap function in c, I don't know how to do it in ruby either
in Ruby something like
a = 1
b = 2
value_swap!(a,b)
puts a #=> 2
puts b #=> 1
The difficulty here is how to use a function to change the value in the main scope.
It's a major hack, but you can try something like this:
def value_swap(a,b,parent_binding)
parent_binding.eval("#{a},#{b}=#{b},#{a}")
end
a=1
b=2
value_swap :a,:b,binding
puts a
puts b
Ruby strings are mutable, so you can have:
a= "43"
b= "42"
def wtf!(a, b)
t= a.clone
a.gsub!(a, b)
b.gsub!(b, t)
end
wtf!(a, b)
puts a, b
Unfortunately, Fixnum is not mutable, so self= n will not work.
Edit: Another example of mutable data structures
Here's another mutable data structure, the array. This might clarify my answer.
a= [43]
b= [42]
def omg!(a, b)
b[0], a[0]= a[0], b[0]
end
omg!(a, b)
p a, b
Ruby supports the parallel assignment of variables which comes in handy if you would like to swap the values of the variables like so:
irb(main):001:0> a = 1
=> 1
irb(main):002:0> b = 2
=> 2
irb(main):003:0> a,b = b,a
=> [1, 2]
irb(main):004:0> a
=> 2
irb(main):005:0> b
=> 1
irb(main):006:0>
But i guess that does not really help with the assignment. In C you would act on references e.g. passing the pointers of those variables to the function and then manipulate them.
If you can't come up with a solution, here is an attempt ( not mine ):
void swap(int *i, int *j) {
int t = *i;
*i = *j;
*j = t;
}
void main() {
int a = 23, b = 47;
printf("Before. a: %d, b: %d\n", a, b);
swap(&a, &b);
printf("After . a: %d, b: %d\n", a, b);
}
Ruby's semantics don't, unless you use trickery, permit what you're trying to do.
For the example you gave, I'd just use parallel assignment, which uses no trickery and will be immediately obvious to the reader of your code:
a, b = b, a

How to determine named group if regex is input by user

str = "cruel world"
#pattern can be /(?<a>.)(?<b>.)/ OR /(?<b>.)(?<a>.)/
#which was inputted by user, we don't know which one will be picked up by user.
pattern = params[:pattern]
please using str.scan(/#{pattern}/) or other match methods expect output:
p a
# ["c", "u", "l", "w", "r"]
p b
# ["r", "e", " ", "o", "l"]
p c
# [ ]
# there is no named group: `?<c>` in this case. However, we should take it if user inputted.
This is my solution:
str = "cruel world"
#case 1
pattern = /(?<a>.)(?<b>.)/
a = Array.new
b = Array.new
c = Array.new
str.scan(/#{pattern}/) do |x|
a << Regexp.last_match(:a) if $~.names.include? "a"
b << Regexp.last_match(:b) if $~.names.include? "b"
c << Regexp.last_match(:c) if $~.names.include? "c"
end
p a
p b
p c
is there a better way?
Here's my solution
def find_named_matches(str, pattern)
names = pattern.names
return Hash[names.zip [[]] * names.size] unless str =~ pattern
Hash[names.zip str.scan(pattern).transpose]
end
And tests
describe 'find_named_matches' do
example 'no matches' do
find_named_matches('abcabcabc', /(?<a>x.)(?<b>.)/).should == {'a' => [], 'b' => []}
end
example 'simple match' do
find_named_matches('abc', /(?<a>.)/).should == {'a' => %w[a b c]}
end
example 'complex name' do
find_named_matches('abc', /(?<Complex name!>.)/).should == {'Complex name!' => %w[a b c]}
end
example 'two simple variables' do
find_named_matches('cruel world', /(?<a>.)(?<b>.)/).should ==
{'a' => %w[c u l w r], 'b' => %w[r e \ o l]}
end
example 'two simple variables' do
find_named_matches('cruel world', /(?<b>.)(?<a>.)/).should ==
{'b' => %w[c u l w r], 'a' => %w[r e \ o l]}
end
example "three variables and matched chars that aren't captured" do
find_named_matches('afk1bgl2chm3', /(?<a>.)(?<f>.)(?<k>.)./).should ==
{'a' => %w[a b c], 'f' => %w[f g h], 'k' => %w[k l m]}
end
example 'complex regex' do
find_named_matches("the dog's hog is the cat's rat", /(?<nouns>(?:(?<=the |'s ))\w+)/).should ==
{'nouns' => %w[dog hog cat rat]}
end
end

Array method that accepts an index and returns a new array with the item at the index removed

'delete_at' and 'slice' remove the item at the index and return that item. But I don't really care about the removed item. I just want a new array with that item removed. Ruby's Array class doesn't seem to provide such a method.
Example would be:
a = ['a','b','c','d']
b = a.remove(2) #b => ['a','b','d']
Here 'remove' is a fictitious method that does what I want. I need the original array, so I want a new array return. I wonder if Ruby already has some built-in like this?
class Array
def remove(idx)
self[0...idx] + self[idx+1..-1]
end
end
a = ['a','b','c','d']
a.reject {|i| i == a[2] }
#=> ["a", "b", "d"]
irb(main):001:0> a = %w[ a b c d ]
#=> ["a", "b", "c", "d"]
irb(main):002:0> a.reject.with_index{ |o,i| i==2 }
#=> ["a", "b", "d"]
irb(main):003:0> a
#=> ["a", "b", "c", "d"]
Requires Ruby 1.9
With some monkey-patching:
irb(main):013:0> class Array
irb(main):014:1> def remove_at(i)
irb(main):015:2> self.dup.tap{ |clone| clone.delete_at(i) }
irb(main):016:2> end
irb(main):017:1> end
#=> nil
irb(main):018:0> a.remove_at(2)
#=> ["a", "b", "d"]
irb(main):019:0> a
#=> ["a", "b", "c", "d"]
it's quite hacky:
a = ['a','b','c','d']
b, = [a, a.delete_at(0)] # => ['b','c','d']
but it's faster(on my eeepc)
require 'benchmark'
n = 5000
Benchmark.bm do |x|
a = (1..5000).to_a
b = nil
x.report { n.times do; b, = [a, a.delete_at(0)]; end }
a = (1..5000).to_a
b = nil
x.report { n.times do; b = a.reject.with_index{ |o,i| i == 0 }; end }
end
user system total real
0.032000 0.000000 0.032000 ( 0.034002)
21.808000 0.156000 21.964000 ( 22.696298) OMG!

Single line multiple assignment in ruby

Is it good to assign an empty array in one line ?
arun#arun:~$ irb
irb(main):001:0> a = b = c = []
=> []
irb(main):002:0> b << "one"
=> ["one"]
irb(main):003:0> p a
["one"]
=> nil
Since i expect 'a' to be [] but it show the value of b means "one". Is this expect one ?
I also try with string and integer object.
irb(main):004:0> d = e = f = 0
=> 0
irb(main):005:0> f = 6
=> 6
irb(main):006:0> p d
0
=> nil
irb(main):007:0>
irb(main):007:0> q = w = e = r = "jak"
=> "jak"
irb(main):008:0> e = "kaj"
=> "kaj"
irb(main):009:0> p w
"jak"
=> nil
irb(main):010:0> p e
"kaj"
=> nil
irb(main):011:0>
It is working as i expected. Then why not array ?
What you are doing is assingning [] to c, which you then assign to b, which finally gets assigned to a.
>> a = b = c = []
>> a.object_id
=> 2152679240
>> b.object_id
=> 2152679240
>> c.object_id
=> 2152679240
What you want is
>> a,b,c = [], [], []
=> [[], [], []]
>> a.object_id
=> 2152762780
>> b.object_id
=> 2152762760
>> c.object_id
=> 2152762740
Edit: the examples work because you just go and plain assign a new value (Fixnums can't be mutated anyway). Try modifying the string in-place instead:
>> q = w = e = r = "jak"
=> "jak"
>> e << 'i'
=> "jaki"
>> w
=> "jaki"
In Ruby everything is an object, including [], 0, and "jak" (an instance of Array, Integer, and String, respectively). You are assigning the same object to multiple variables -- if you change that object (b << "one"), then every variable referencing that object will reflect the change. When you use the assignment operator = you are not changing the object -- you are assigning a new object to the variable.
In Michael Kohl's last example (), he is using << which modifies the String object referenced by the variable. That is why the variable still references the same object and all strings referencing that object reflect the change.

Resources