Extracting Values from a Hash

Ruby : Extract Key and Value from hash

I'd say that the most elegant way to go about this is probably to convert data into a Hash first (assuming there are never any duplicate keys), like so:

data = data.map { |x| [x['key'], x['value']] }.to_h
# => {"Name"=>"Jason", "Age"=>"21", "last_name"=>"bourne"}

The #to_h method expects each element of the array to be an array in the form [key, value], so the #map call processes each element of data to convert it into that form.

Once this has been done, you can simply access keys like any other hash:

data['Name'] # => "Jason"
data['Age'] # => "21"

How to extract value from hash in Rails

@value_hash is not a hash, it's an ActiveRecord::Relation (as the error states).

In your example, @value_hash has only one member. To get that member, which is an instance of the class CustomValue (which is still not a hash!), you can do:

custom_value = @value_hash.first

Then, to get the year, you can do:

custom_value.year

Or, you could do it in one shot as:

@value_hash.first.year

Which is just a long way of saying exactly what Sachin R said (so you should accept their answer).

How to extract values from hashes into separate arrays?

A simple solution is to iterate the array of hashes and add the required values to two separate arrays:

months = []
counts = []
array_of_hash.each do |hash|
months << hash["month"]
counts << hash["count"]
end

But you could also use each_with_object

months, count = array_of_hash.each_with_object([[], []]) do |hash, accu|
accu[0] << hash["month"]
accu[1] << hash["count"]
end

or iterate twice and get the months and counts separately:

months = array_of_hash.map { |hash| hash["month"] }
counts = array_of_hash.map { |hash| hash["count"] }

How to extract a value from a hash

The keys method returns an array of the key names; it doesn't return the values.

Given these inputs:

json = '{"user1":{"about_you":"jjhj","age":18,"email":18},"user2":{"about_you":"jjhj","age":18,"email":18},"user3":{"about_you":"jjhj","age":18,"email":18}}'
data_hash = JSON.parse(json)

Try just iterating over the hash's keys and values:

data_hash.each { |k,v| puts v['email'] }

Or if you prefer:

data_hash.each do |k,v|
puts v['email']
end

Each returns:

18
18
18

Extract values from Ruby data hash and concatenate values into single continuous String

As your input (h) is a hash that can contain hashes in its values, you can implement the method to extract the strings from the values using recursion:

input = {a: "da", b: {c:"test", e: {f: "bird"}}, d:"duck"}

def extract_values_from_hash(input)
return input unless input.is_a?(Hash)

input.flat_map { |_, v| extract_values_from_hash(v) }
end

extract_values_from_hash(input).join
# datestbirdduck

What it does is to receive the hash (input) from which extract the values adding a guard clause - as the base case, which returns the argument the method was called with if it's a hash object, otherwise it flattens and map the object invoking the method itself. This way you extract every value from the initial method argument.

Notice this extracts anything that's in the input that's not directly a hash, if you happen to have an object like this:

{a: "da", b: {c:"test", e: {f: "bird"}}, d:"duck", g: 1, h: [{i: "hola"}, {j: "chao"}]}

The result would be:

"datestbirdduck1{:i=>\"hola\"}{:j=>\"chao\"}"

Extract the hash value substring from each line in a TextBox

I've done quite a bit of work to reduce your code down to the bare essentials of computing your hashes without relying on the UI. I've then got the code that requires the UI separated out so that it has nothing to do with computing hashes.

To start with I created a single hashing function that you can use to compute any hash.

public Task<string> ComputeHash(string file, Func<HashAlgorithm> create)
{
return Task.Run(() =>
{
using (var crypto = create())
{
using (var stream = File.OpenRead(file))
{
return String.Concat(
crypto.ComputeHash(stream).Select(x => x.ToString("X2")));
}
}
});
}

I've now created two fields to store the list of files and the resulting hashes.

private string[] _fileNames = null;
private string[] _hashes = null;

I'll show the code that sets the _fileNames array later, but for now this is the code that you can call to compute your hashes:

private async Task<String> Run(bool md5, bool sha1, bool sha256, bool sha512)
{
File.Delete(Path.Combine(Environment.CurrentDirectory, "log.txt"));

Func<HashAlgorithm> hashAlgorithm = null;
if (md5) hashAlgorithm = () => MD5.Create();
else if (sha1) hashAlgorithm = () => SHA1.Create();
else if (sha256) hashAlgorithm = () => SHA256.Create();
else if (sha512) hashAlgorithm = () => SHA512.Create();

if (hashAlgorithm == null)
{
return "No hash algorithm selected.";
}
else if (_fileNames == null || _fileNames.Length == 0)
{
return "No file selected." + "\n";
}
else if (_fileNames.Any(f => !File.Exists(f)))
{
return "Invalid filename." + "\n";
}
else
{
var tasks = _fileNames.Select(f => ComputeHash(f, hashAlgorithm)).ToArray();
_hashes = await Task.WhenAll(tasks);
return "Success";
}
}

The hardest part of this code, in my opinion, is the use of Func<HashAlgorithm> hashAlgorithm to store the hashing algorithm. If you're not familiar with a Func<> then it's worth looking up, but think of it as a way to store a function in a variable so that you can call the function later.

Now, finally, we have the two bits of code that interact with the UI:

private void filePickerButton_Click(object sender, RoutedEventArgs e)
{
CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.InitialDirectory = "C:\\Users";
dialog.IsFolderPicker = false;
dialog.Multiselect = true;

if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
{
_fileNames = dialog.FileNames.ToArray();
filePicketTextBox.Text = string.Join("\n", dialog.FileNames);
}
else
{
outputTextBox.Text = "Operation cancelled." + "\n";
}
}

private async void runButton_Click(object sender, RoutedEventArgs e)
{
string result = await Run(
md5CheckBox.IsChecked,
sha1CheckBox.IsChecked,
sha256CheckBox.IsChecked,
sha512CheckBox.IsChecked);

outputTextBox.Text = result;
}

The end result is that you have two arrays, _fileNames & _hashes that you can use to get the hash for each file name. No need for splitting text.

Extracting values from a hash

Try the following:

#!/usr/bin/env ruby

require 'httparty'

(HOST, ID, VERSION) = ARGV

class MyApi
include HTTParty
format :json
end

response = MyApi.get("http://#{HOST}/v1/dc/manifest/#{ID}/#{VERSION}")

puts response.inspect

The addition of the format :json tells HTTParty to parse the response as JSON. Then you'll get a hash you can iterate over properly.

Extracting value from nested hashes and arrays in Ruby

Short alternative way using Array#transpose method:

> h.values.flatten(1).transpose.last
=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]

# with to number conversion
> h.values.flatten(1).transpose.last.map(&:to_i)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Benchmarks

require 'benchmark'

h = {
a: [ ["c", "1"],["d","2"],["e","3"],["f","4"] ],
b: [ ["g","5"],["h","6"],["i","7"],["j","8"] ],
c: [ ["k","9"],["l","10"],["m","11"],["n","12"] ]
}

Benchmark.bm(10) do |x|
x.report("transpose") do
1000.times { h.values.flatten(1).transpose.last.map(&:to_i) }
end
x.report("collect/map") do
1000.times { h.values.flatten(1).collect(&:last).map(&:to_i) }
end
x.report("regexp") do
1000.times { h.values.flatten.select { |v| v.match(/\d/) }.map(&:to_i) }
end
x.report("Integer") do
1000.times { h.values.flat_map { |a| a.map { |_,e| Integer(e) } } }
end
end

Results

                 user     system      total        real
transpose 0.000000 0.000000 0.000000 ( 0.006971)
collect/map 0.010000 0.000000 0.010000 ( 0.007490)
regexp 0.030000 0.010000 0.040000 ( 0.031939)
Integer 0.010000 0.000000 0.010000 ( 0.006832)


Related Topics



Leave a reply



Submit