This question already has answers here:
How do I copy a hash in Ruby?
(13 answers)
Closed 2 years ago.
See this IRB code :
2.6.6 :107 > h = {}
=> {}
2.6.6 :108 > a = []
=> []
2.6.6 :109 > h["name"] = "hans"
=> "hans"
2.6.6 :110 > a << h
=> [{"name"=>"hans"}]
2.6.6 :111 > h["name"] = "paul"
=> "paul"
2.6.6 :112 > a
=> [{"name"=>"paul"}]
2.6.6 :113 >
But this is not that what I want, when I overwrite the h Hash, I don't want to overwrite the already added value to the array ! ! !
Perhaps you wanted this:
2.6.6 :107 > h = {}
=> {}
2.6.6 :108 > a = []
=> []
2.6.6 :109 > h["name"] = "hans"
=> "hans"
2.6.6 :110 > a << h.clone
=> [{"name"=>"hans"}]
2.6.6 :111 > h["name"] = "paul"
2.6.6 :112 > a
=> [{"name"=>"hans"}]
Related
I just noticed that if you don't either clear or replace a string, the memory usage doesn't reduce.
File x.rb:
#!/usr/bin/ruby -w
raise(RuntimeError, 'A GNU/Linux or an Android system is needed') unless /linux/ === RUBY_PLATFORM.downcase
require 'objspace'
STDOUT.sync = true
GC.start(full_mark: true, immediate_sweep: true)
define_method(:show) { "System Memory Usage: #{::IO.readlines('/proc/meminfo').then { |x| [x[0], x[2]] }
.map { |x| x.split[1].to_f }.reduce(:-)./(1024).round(3)} MiB "\
"| Available: #{::IO.readlines('/proc/meminfo')[2].split[1].to_f./(1024).round(3)} MiB" }
define_method(:memsize) { |obj| ObjectSpace.memsize_of(obj).to_s.reverse.gsub(/\d{1,3}/).to_a.join(',').reverse << ' Bytes'}
File y.rb:
#!/usr/bin/ruby -w
fail(NoMemoryError, 'Not enough available memory') if ::IO.readlines('/proc/meminfo')[2].split[1].to_i < 600_000
require_relative(File.join(__dir__, 'x'))
puts show
a = '0' * 500_000_000
puts "Memory used by a: #{memsize(a)}"
puts show
a = ''
puts "Memory used by a: #{memsize(a)}"
puts show
File z.rb:
#!/usr/bin/ruby -w
fail(NoMemoryError, 'Not enough available memory') if ::IO.readlines('/proc/meminfo')[2].split[1].to_i < 600_000
require_relative(File.join(__dir__, 'x'))
puts show
a = '0' * 500_000_000
puts "Memory used by a: #{memsize(a)}"
puts show
a.clear
puts "Memory used by a: #{memsize(a)}"
puts show
Output of y.rb:
System Memory Usage: 2316.289 MiB | Available: 1445.23 MiB
Memory used by a: 500,000,041 Bytes
System Memory Usage: 2795.504 MiB | Available: 966.016 MiB
Memory used by a: 40 Bytes
System Memory Usage: 2795.504 MiB | Available: 966.016 MiB
Output of z.rb:
System Memory Usage: 2301.359 MiB | Available: 1460.16 MiB
Memory used by a: 500,000,041 Bytes
System Memory Usage: 2780.098 MiB | Available: 981.422 MiB
Memory used by a: 40 Bytes
System Memory Usage: 2303.387 MiB | Available: 1458.133 MiB
Now the problem despite assigning a to an empty string, running the file y.rb uses around 500 megs of memory until the program exits.
z.rb clears the string.
This doesn't also clears the memory:
a[0..-1] = ''
Note that both my program and gnome-system-monitor agrees with the system RAM usage.
Why is this the case? How does clear works when assignment operator doesn't?
a = '' and a.clear do subtly different things.
a = '' creates a new String object and assigns it to a. The old String object is still floating around in memory waiting to be garbage collected.
2.4.4 :010 > a = 'foo'
=> "foo"
2.4.4 :011 > a.object_id
=> 70311739468740
2.4.4 :012 > a = ''
=> ""
2.4.4 :013 > a.object_id
=> 70311748786840
Note the different object IDs.
a.clear clears the existing String object.
2.4.4 :016 > a = 'foo'
=> "foo"
2.4.4 :017 > a.object_id
=> 70311748749240
2.4.4 :018 > a.clear
=> ""
2.4.4 :019 > a.object_id
=> 70311748749240
Note the object ID is the same.
Specifically clear calls str_discard which immediately frees the memory allocated to the String.
static inline void
str_discard(VALUE str)
{
str_modifiable(str);
if (!STR_EMBED_P(str) && !FL_TEST(str, STR_SHARED|STR_NOFREE)) {
ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
RSTRING(str)->as.heap.ptr = 0;
RSTRING(str)->as.heap.len = 0;
}
}
Another way to see the difference...
2.4.4 :026 > a = 'foo'
=> "foo"
2.4.4 :027 > b = a
=> "foo"
2.4.4 :028 > a.object_id
=> 70311748602540
2.4.4 :029 > b.object_id
=> 70311748602540
a and b point at the same underlying object.
2.4.4 :030 > a = ''
=> ""
2.4.4 :031 > b
=> "foo"
2.4.4 :032 > a.object_id
=> 70311748541360
2.4.4 :033 > b.object_id
=> 70311748602540
After a = '', a points at a new object while b points at the original. This illustrates why a = '' cannot free memory immediately, something else might be referencing the original String.
If we set that up again...
2.4.4 :034 > a = 'foo'
=> "foo"
2.4.4 :035 > b = a
=> "foo"
2.4.4 :036 > a.object_id
=> 70311748490260
2.4.4 :037 > b.object_id
=> 70311748490260
But this time use a.clear...
2.4.4 :038 > a.clear
=> ""
2.4.4 :039 > b
=> ""
2.4.4 :040 > a.object_id
=> 70311748490260
2.4.4 :041 > b.object_id
=> 70311748490260
a and b are still both refer to the same object.
I have two variables which sometimes contain double data structure value. How can I determine in Ruby that a variable is having double value?
For example,
a = 3.4
a.is_a_double #=> true
a = "dadadad#asdasd.net"
a.is_a_double #=> false?
You should be able to use any of following method to know this:
is_a?
kind_of?
instance_of?
See uses:
2.2.2 :009 > a = 4.5
=> 4.5
2.2.2 :010 > a.is_a? Float
=> true
2.2.2 :011 > a.kind_of? Float
=> true
2.2.2 :015 > a.instance_of? Float
=> true
What is the proper way to build a string dynamically using items from an array. Currently I am building it using this;
#ar.each do |b|
#str = #str + "select '#{b[0]}' as SourceGUID, '#{b[1]}' as SourceFileName, '#{b[2]}' as FullPath, #{b[3]} as SizeInMB, #{b[4]} as ItemCount, #{b[5]} as ParentCount, #{b[6]} as ChildCount, '#{b[7]}' as CaseName, #{b[8]} as ProcessedSizeMB\n union all\n"
end
This is obviously a horrible way to do it. Is there a way to achieve it using .join?
A draft
2.3.1 :028 > row = %w(my_id my_name my_age)
=> ["my_id", "my_name", "my_age"]
2.3.1 :029 > aliases = %w(id name age)
=> ["id", "name", "age"]
2.3.1 :030 > fields = row.zip aliases
=> [["my_id", "id"], ["my_name", "name"], ["my_age", "age"]]
2.3.1 :031 > fields.map do |field|
2.3.1 :032 > field[0] = "'#{field[0]}'"
2.3.1 :033?> field.join(" AS ")
2.3.1 :034?> end.join(", ")
=> "'my_id' AS id, 'my_name' AS name, 'my_age' AS age"
v = { "foo"=>"bar"}
v["foo"] // bar
Say,
k = {:bar => 1}
>k[:bar] // 1
But,
k[v["foo"]] // nil
how to access key ==> value ( k[ key ] = value ) from hashes using a variable, say v["foo"]
You'll need to run to_sym on the result of v["foo"] in order to the the value in k:
1.9.3p484 :007 > v = { "foo"=>"bar"}
=> {"foo"=>"bar"}
1.9.3p484 :008 > k = {:bar => 1}
=> {:bar=>1}
1.9.3p484 :009 > k[v["foo"].to_sym]
=> 1
This question already has answers here:
Strange, unexpected behavior (disappearing/changing values) when using Hash default value, e.g. Hash.new([])
(4 answers)
Closed 7 years ago.
Code example below. Calling append on a hash value returns correctly but the hash itself doesn't behave as I would expect.
ruby-1.9.2-p290 :037 > r = {}
=> {}
ruby-1.9.2-p290 :038 > r.default = []
=> []
ruby-1.9.2-p290 :039 > r["c"] << 1
=> [1]
ruby-1.9.2-p290 :040 > r["c"]
=> [1]
ruby-1.9.2-p290 :041 > r
=> {}
ruby-1.9.2-p290 :042 > r.empty?
=> true
from the doc on default=:
Sets the default value, the value returned for a key that does not
exist in the hash. It is not possible to set the default to a Proc
that will be executed on each key lookup.
So you can use this:
irb(main):037:0> h = Hash.new { |hash, key| hash[key] = [] }
=> {}
irb(main):038:0> h[1] << "2"
=> ["2"]
irb(main):039:0> h
=> {1=>["2"]}
also you can use default_proc:
irb(main):047:0> h = {}
irb(main):047:0> h.default_proc = proc {|hash, key| hash[key] = []}
=> #<Proc:0x23939a0#(irb):47>
irb(main):049:0> h[1] << 3
=> [3]
irb(main):050:0> h
=> {1=>[3]}
It seems ruby hash uses r.default as default value for any r[<unassigned-key>]. So a single value is changed even if you specify different un-assigned keys. Please see below:
irb(main):001:0> r = {}
=> {}
irb(main):002:0> r.default = []
=> []
irb(main):003:0> r["c"] << 1
=> [1]
irb(main):004:0> r["c"]
=> [1]
irb(main):005:0> r["b"] << 2
=> [1, 2]
irb(main):006:0> r["b"]
=> [1, 2]
irb(main):007:0> r["c"]
=> [1, 2]
irb(main):010:0> r.default
=> [1, 2]
irb(main):008:0> r
=> {}
irb(main):009:0> r.empty?
=> true