0

In my Ruby code, a long hex string is parsed and pushed into a data array (avl_data_array.push(avl_data)). After pushing, when I use puts to display the array, all the elements are the same...

The code is:

data_hex_string = '03D8CAFE01D0000F383630323634303535353134323532081100000180BB016382005B29ED2AEF935C0D00000000000000000C0616004701F0001502C800EF000643273A440000B50012B60010422F2B180000000000000180BACA745E005B29ED2AEF935C0D003000000B0000000C0616004703F0001503C800EF00064326A2440000B5000CB60008422F41180000000000000180BA938536005B29ED2AEF935C0D00270000090000000C0616004703F0001503C800EF0006432705440000B5000CB60008422F19180000000000000180BA5C960E005B29ED2AEF935C0D003200000B0000000C0616004703F0001504C800EF00064328A4440033B5000BB60008422EEC180000000000000180BA1F8371005B29ED2AEF935C0D000000000000000008041600F000C801EF00044326B7440000422F73180000000000000180B9E89182005B29ED2AEF935C0D000000000000000008041600F000C801EF000443268B440000422F30180000000000000180B9B19F93005B29ED2AEF935C0D000000000000000008041600F000C801EF0004432690440000422EED180000000000000180B97AB11B005B29ED2AEF935C0D00000000000000000C0616004703F0001503C801EF0006432672440000B50000B60000422F31180000000000000180B943C385005B29ED2AEF935C0D00000000000000000C0616004703F0001503C801EF0006432681440000B50000B60000422EDA180000000000000180B90CD40F005B29ED2AEF935C0D00000000000000000C0616004703F0001504C801EF0006432681440000B50000B60000422F26180000000000000180B8D5E778005B29ED2AEF935C0D00000000000000000C0616004703F0001504C801EF0006432677440000B50000B60000422F30180000000000000180B89EF589005B29ED2AEF935C0D000000000000000008041600F000C801EF0004432681440000422F30180000000000000180B868034C005B29ED2AEF935C0D00000000000000000C0616004703F0001503C801EF000643267C440000B50000B60000422F0A180000000000000180B83111AB005B29ED2AEF935C0D000000000000000008041600F000C801EF000443267C440000422F3A180000000000000180B7FA1ECA005B29ED2AEF935C0D00000000000000000C0616004704F0001503C801EF0006432681440000B50000B60000422F1D180000000000000180B7C332F5005B29ED2AEF935C0D00000000000000000C0616004704F0001504C801EF0006432686440000B50000B60000422F30180000000000000180B78C431E005B29ED2AEF935C0D000000000000000008041600F000C801EF0004432686440000422F8F180000000011'

avl_data_header = {}
avl_data = {}
avl_data_array = [] 
avl_data_footer = {}

avl_data_header[:packet_len] = data_hex_string[0..3]
avl_data_header[:packet_id] = data_hex_string[4..7]
avl_data_header[:not_usable_byte] = data_hex_string[8..9]
avl_data_header[:avl_packet_id] = data_hex_string[10..11]
avl_data_header[:imei_len] = data_hex_string[12..15]

imei_len_dec = data_hex_string[12..15].to_i(16)
current_add = 16
offset = imei_len_dec * 2
avl_data_header[:imei] = data_hex_string[current_add..(current_add+offset-1)]

current_add = current_add+offset
offset = 2
avl_data_header[:codec_id] = data_hex_string[current_add..(current_add+offset-1)]

current_add = current_add+offset
offset = 2
avl_data_header[:number_data1] = data_hex_string[current_add..(current_add+offset-1)]

data_num = avl_data_header[:number_data1].to_i(16)

for a in 0..(data_num-1) do
  current_add = current_add+offset
  offset = 2 * 8
  avl_data[:timestamp] = data_hex_string[current_add..(current_add+offset-1)]

  current_add = current_add+offset
  offset = 2
  avl_data[:priority] = data_hex_string[current_add..(current_add+offset-1)]

  current_add = current_add+offset
  offset = 2 * 4
  avl_data[:longitude] = data_hex_string[current_add..(current_add+offset-1)]

  current_add = current_add+offset
  offset = 2 * 4
  avl_data[:latitude] = data_hex_string[current_add..(current_add+offset-1)]

  current_add = current_add+offset
  offset = 2 * 2
  avl_data[:altitude] = data_hex_string[current_add..(current_add+offset-1)]

  current_add = current_add+offset
  offset = 2 * 2
  avl_data[:angle] = data_hex_string[current_add..(current_add+offset-1)]

  current_add = current_add+offset
  offset = 2
  avl_data[:satellites] = data_hex_string[current_add..(current_add+offset-1)]

  current_add = current_add+offset
  offset = 2 * 2
  avl_data[:speed] = data_hex_string[current_add..(current_add+offset-1)]
  
  avl_data_array.push(avl_data)
end

current_add = current_add+offset
offset = 2
avl_data_footer[:number_data2] = data_hex_string[current_add..(current_add+offset-1)]

current_add = current_add+offset
offset = 2 * 4
avl_data_footer[:crc_16] = data_hex_string[current_add..(current_add+offset-1)]
    
puts "header: #{avl_data_header}"
puts "data:"
puts avl_data_array
puts "footer: #{avl_data_footer}"

The result is:

header: {:packet_len=>"03D8", :packet_id=>"CAFE", :not_usable_byte=>"01", :avl_packet_id=>"D0", :imei_len=>"000F", :imei=>"383630323634303535353134323532", :codec_id=>"08", :number_data1=>"11"}
data:
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
{:timestamp=>"ED18000000000000", :priority=>"01", :longitude=>"80B97AB1", :latitude=>"1B005B29", :altitude=>"ED2A", :angle=>"EF93", :satellites=>"5C", :speed=>"0D00"}
footer: {:number_data2=>"00", :crc_16=>"00000000"}

The element in array data should be different. I am Ruby newbie, but it seems the grammer in my code is correct. Why this happens?

1
  • Do you really need that much code to reproduce the problem? Commented May 16, 2022 at 8:56

1 Answer 1

3

Why this happens?

You never change avl_data. It is always the same object. Hence, you push the same object to the Array in avl_data_array over and over again.

Here is a reduced version of your code demonstrating the problem more clearly:

single_array_element = {}
array = []

3.times do |i|
  single_array_element[:i] = i
  array << single_array_element
end

array.all? {|el| single_array_element.object_id == el.object_id}
#=> true

array
#=> [{ i: 2 }, { i: 2 }, { i: 2 }]

I am Ruby newbie, but it seems the grammer in my code is correct.

The syntax is indeed correct, otherwise the program would not even run – the parser would abort with a SyntaxError. But the semantics aren't: The code you wrote is 100% valid Ruby code, it is not an error.

Ruby is doing exactly what you are telling her to do, you just told it to do the wrong thing.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. @Jorg, I do not understand why I never change avl_data. It looks like avl_data is changed every time in the loop. If add "puts single_array_element" in the look of your reduced version, it display {:i=>0}{:i=>1}{:i=>2}
You mutate the Hash that is referenced by avl_data. But you never change avl_data. You assign a Hash to it on line 4, and then never assign to it again, which means during the entire runtime of your program, there is only that single Hash which you keep appending to avl_data_array over and over again.
@leilei "changing avl_data" can mean two very different things: 1) mutating the hash, avl_data is referring to (changing the existing values). 2) assigning a new hash to the avl_data variable (which is what Jörg means when saying "you never change avl_data"). If you add the same hash object multiple times (what you did), then changing its values will affect all elements (because they are the same object). In order to get different objects, you have to create a new hash instance each time, e.g. by moving avl_data = {} into the loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.