Can you optimize this descending sorting array with Ruby? - ruby

Do you know a better, faster, smarter, efficent or just more elegat way of doing the following ?
due this array
a = [171, 209, 3808, "723", "288", "6", "5", 27, "22", 207, 473, "256", 67, 1536]
get this
a.map{|i|i.to_i}.sort{|a,b|b<=>a}
=> [3808, 1536, 723, 473, 288, 256, 209, 207, 171, 67, 27, 22, 6, 5]

You can use in-place mutations to avoid creating new arrays:
a.map!(&:to_i).sort!.reverse!
Hard to know if it's faster or more efficient without a benchmark, though.

Here's one using symbol#to_proc
a.map(&:to_i).sort.reverse
This is faster than using in-place modifier (!) methods but uses more memory. As a bonus, it keeps the original array a intact if you want to do anything else with it.

Related

Bash - extract substring in a string with special characters

I'm trying to extract 43 (downloader/request_count result) in the string below:
OUT="[scrapy.statscollectors] INFO: Dumping Scrapy stats: {'downloader/request_bytes': 21394, 'downloader/request_count': 43, 'downloader/request_method_count/GET': 43, 'downloader/response_bytes': 1030981, 'downloader/response_count': 43, 'downloader/response_status_count/200': 43, 'item_scraped_count': 41"
In a first step, I did value=${OUT#*request_count\':}, which return:
43, 'downloader/request_method_count/GET': 43, 'downloader/response_bytes': 1030981, 'downloader/response_count': 43, 'downloader/response_status_count/200': 43, 'item_scraped_count': 41
But when I try to delete right part, I get an error:
value2=${value%,*}
or
value2=$(cut -d, -f1 $value)
Any ideas?
Thanks in advance for your help!
% removes the shortest possible string, use %% to remove the longest possible one:
value2=${value%%,*}
# ~~
Also, you might want to remove the space after the colon, too:
value=${OUT#*request_count\': }
# ~

Bytes vs codepoints in ruby

What is the difference between ruby string functions:- codepoints and bytes
'abcd'.bytes
=> [97, 98, 99, 100]
'abcd'.codepoints
=> [97, 98, 99, 100]
bytes returns individual bytes, regardless of char size, whereas codepoints returns unicode codepoints.
s = '日本語'
s.bytes # => [230, 151, 165, 230, 156, 172, 232, 170, 158]
s.codepoints # => [26085, 26412, 35486]
s.chars # => ["日", "本", "語"]
I see where your confusion arises from. Ruby uses utf-8 encoding by default now and utf-8 was specifically designed so that its first codepoints (0-127) are exactly the same as in ASCII encoding. ASCII is an encoding with one-byte chars, so in examples in your question methods bytes and codepoints return the same values, coincindentally.
So, if you need to break string into characters, use either chars or codepoints (whichever is appropriate for your use case). Use bytes only when you treat string as an opaque binary blob, not text.
Actually, chars (suggested above) might not be accurate enough, since unicode has notion of combining characters and modifier letters. If you care about this, you need to use so-called "grapheme clusters". Here's an example (taken from this answer:
s = "a\u0308\u0303\u0323\u032d"
s.bytes # => [97, 204, 136, 204, 131, 204, 163, 204, 173]
s.codepoints # => [97, 776, 771, 803, 813]
s.chars # => ["a", "̈", "̃", "̣", "̭"]
s.grapheme_clusters # => ["ạ̭̈̃"] # rendering of this glyph is kinda broken, which illustrates the point that unicode is hard

Converting String Object to Bytes and vice-versa using packer/unpacker Ruby

I want to convert a string object to bytes and Vice-versa.
Is it possible using Ruby Packer/Unpacker?
I am unable to find the format specifier to use
*pack_object = "Test".pack('**x**')* where x is format specifier
*unpacked_object = pack_object.unpack('**x**')* , this should result in "Test" string
String has a bytes method that returns an array of integers:
'Type'.bytes
#=> [84, 121, 112, 101]
The equivalent unpack directive is C*: (as already noted by cremno)
'Type'.unpack('C*')
#=> [84, 121, 112, 101]
Or the other way round:
[84, 121, 112, 101].pack('C*')
#=> "Type"
Note that pack returns a string in binary encoding.
Regarding your comment:
The output which i need is the same strung which i packed
pack and unpack are counterparts, so you can use all kind of directives:
'Type'.unpack('b*')
#=> ["00101010100111100000111010100110"]
['00101010100111100000111010100110'].pack('b*')
#=> 'Type'

How to set multiple values for a key in a hash in prototype.js?

How to set multiple values for a key in a hash in prototype.js?
For Eg:
var hash={2005: [107, 31, 635, 203, 2]}
you can take exactly what you have written and convert to a Hash like this
var hash=$H({2005: [107, 31, 635, 203, 2]});
console.log(hash.get(2005));
//returns [107, 31, 635, 203, 2] as an array

Create binary data using Ruby?

i was palying with the ruby sockets, so i ended up trying to put an IP packet togather, then i took an ip packet and try to make a new one just like it.
now my problem is: if the packet is: 45 00 00 54 00 00 40 00 40 01 06 e0 7f 00 00 01 7f 00 00 01, and this is obviously hexadecimal, so i converted it into a decimal, then into a binary data using the .pack method, and pass it up to the send method, then the Wireshark shows me a very strange different thing from what i created, i doing something wrong ???, i know that, but can't figure it out:
#packet = 0x4500005400004000400106e07f0000017f000001 #i converted each 32 bits together, not like i wrote
#data = ""
#data << #packet.to_s
#socket.send(#data.unpack(c*).to_s,#address)
and is there another way to solve the whole thing up, can i for example write directly to the socket buffer the data i want to send??
thanks in advance.
Starting with a hex Bignum is a novel idea, though I can't immediately think of a good way to exploit it.
Anyway, trouble starts with the .to_s on the Bignum, which will have the effect of creating a string with the decimal representation of your number, taking you rather further from the bits and not closer. Somehow your c* seems to have lost its quotes, also.
But putting them back, you then unpack the string, which gets you an array of integers which are the ascii values of the digits in the decimal representation of the numeric value of the original hex string, and then you .to_s that (which IO would have done anyway, so, no blame there at least) but this then results in a string with the printable representation of the ascii numbers of the unpacked string, so you are now light-years from the original intention.
>> t = 0x4500005400004000400106e07f0000017f000001
=> 393920391770565046624940774228241397739864195073
>> t.to_s
=> "393920391770565046624940774228241397739864195073"
>> t.to_s.unpack('c*')
=> [51, 57, 51, 57, 50, 48, 51, 57, 49, 55, 55, 48, 53, 54, 53, 48, 52, 54, 54, 50, 52, 57, 52, 48, 55, 55, 52, 50, 50, 56, 50, 52, 49, 51, 57, 55, 55, 51, 57, 56, 54, 52, 49, 57, 53, 48, 55, 51]
>> t.to_s.unpack('c*').to_s
=> "515751575048515749555548535453485254545052575248555552505056505249515755555157565452495753485551"
It's kind of interesting in a way. All the information is still there, sort of.
Anyway, you need to make a binary string. Either just << numbers into it:
>> s = ''; s << 1 << 2
=> "\001\002"
Or use Array#pack:
>> [1,2].pack 'c*'
=> "\001\002"
First check your host byte order because what you see in wireshark is in network byte order (BigEndian). Then in wireshark you will be seeing protocol headers (depends upon whether it is TCP socket or a UDP one) followed by data. You can not directly send IP packets. So you can see this particular data in the particular's packet's data section i.e. (data section of TCP/UDP packet).

Resources