4

I have a list of json objects something like this:

test = [{"a": 1, "b": 2, "c": 3}, {"a": 4, "b": 5, "c":6}]

I want to fetch the fields 'a' and 'c' from the above test list to create a list of list something like this:

[[1, 4], [3, 6]]

The idea is to make a list of all the values of a, then the values of c.

When I am using pluck:

test.pluck(:a, :c)

I am getting output like this:

[[1, 3], [4, 6]]

One approach I tried which is working fine.

res = []
res << test.pluck(:a)
res << test.pluck(:c)

But I am thinking it would be better if I get one or two liner solution,
with or without inbuilt function because the number of fields in the future may increase.

1
  • Good question, but “...”fields 'a' and 'c'” should be “fields :a and :c”. It would be better to assign a variable to an array of those keys (e.g., target = [:a, :b]), so that readers could refer to that variable in answers and comments without having to define it ( just as they can refer to test). Commented Oct 7, 2019 at 15:21

2 Answers 2

8

You were looking for following,

%i(a c).map { |x| test.map { |e| e[x] } }
Sign up to request clarification or add additional context in comments.

7 Comments

It is working perfect. Can you please explain it a little bit?
first check how map works to provide data in array, so then test this -> test.map { |e| e[:a] } which will provide you [1, 4] so for :c so I have iterated this code on one more map iterated on [:a, :c] array which provided array of array.
@ray, sorry, I didn't see the big difference between [[1, 4], [3, 6]] and [[1, 3], [4, 6]].
@SebastianPalma I guess, me too
My initial reaction was that this was relatively inefficient, but since hash lookups are very fast and have a computational complexity close to O(1), if nis the number of keys of interest (2 in the example), your solution has a computational complexity close to the minimum possible of O(n*test.size). Moreover, your solution reads well, but would read better, and be slightly more efficient, if you were to adopt @3limin4t0r‘s suggestion. Good answer.
|
4

You could use Array#transpose on the pluck result. Which assumes the array represents rows or columns and swaps the representation around.

test.pluck(:a, :c).transpose
#=> [[1, 4], [3, 6]]

2 Comments

...the pure Ruby equivalent being test.map { |h| h.values_at(:a, :c) }.transpose. Good answer.
@CarySwoveland Yep, but OP already uses pluck and tagged the question with ruby-on-rails, so I went with pluck since it's a lot shorter. But providing a pure Ruby equivalent doesn't hurt, and is useful for readers who don't use Rails.

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.