-3

I have four arrays of equal length:

a = [1, 2, 3, 4, 5]
b = ['A', 'B', 'C', 'D', 'E']
c = ['J', 'K', 'L', 'M', 'N']
d = ['v', 'w', 'x', 'y', 'z']

and I want to get an array of all possible combination by taking one element from each of the arrays:

[
  [1, 'A', 'J', 'v'], 
  [2, 'A', 'J', 'v'], 
  [3, 'A', 'J', 'v'],
  ...
]

I'm doing this:

master_array = []

for i in first_names do
    sub_array = []
    for j in last_names do
        for k in city do
            for l in state do
                sub_array.push(i, j, k, l)
            end
        end
    end
    master_array.push(sub_array)
end

master_array

Ideally I would like to return an array of hashes, whose keys are the names of the arrays, like so:

[
  {a: 1, b: 'A', c: 'J', d: 'v'}, 
  {a: 2, b: 'A', c: 'J', d: 'v'}, 
  {a: 3, b: 'A', c: 'J', d: 'v'},
  ...
]
sawa
  • 165,429
  • 45
  • 277
  • 381
Naji
  • 674
  • 2
  • 14
  • 35
  • 4
    Have you tried anything so far? StackOverflow isn't a free code-writing service, and expects you to [try to solve your own problem first](http://meta.stackoverflow.com/questions/261592). Please update your question to show what you have already tried, showing the specific problem you are facing in a [minimal, complete, and verifiable example](http://stackoverflow.com/help/mcve). For further information, please see [how to ask a good question](http://stackoverflow.com/help/how-to-ask), and take the [tour of the site](http://stackoverflow.com/tour) – Jaromanda X Jan 22 '18 at 03:33
  • What is your current brute-force approach? – guest271314 Jan 22 '18 at 03:35
  • Welcome to Stack Overflow. This is not a code/SQL/regex writing service, where you post a list of your requirements and language of choice and a code monkey churns out code for you. We're more than happy to help, but we expect you to make an effort to solve the problem yourself first. Once you've done so, you can explain the problem you're having, include the **relevant** portions of your work, and ask a specific question, and we'll try to help. Good luck. – Ken White Jan 22 '18 at 03:39
  • Currently I have an empty `master_array=[]` and a function with four for-loops nested within each other, creating a `sub_array` that holds a combination of `a[0], b[0], c[0], d[0]`, then `a[0], b[0], c[0], d[1]`, `a[0], b[0], c[0], d[2]` so on and so forth – Naji Jan 22 '18 at 03:40
  • I didnt think to post it but I will update my answer now – Naji Jan 22 '18 at 03:41
  • 4
    I don't know about efficiency but in Ruby you can write `a.product(b,c,d)` to get your combinations. – Sagar Pandya Jan 22 '18 at 03:41
  • Does your current code return the expected result? – guest271314 Jan 22 '18 at 03:43
  • I second the first comment. But "brute force" is the sensible and really *only* approach to this type of problem. There's no way to avoid a nested iteration of each of the arrays. Using some library function if there is one, will only do the same thing under the hood. – see sharper Jan 22 '18 at 03:45
  • @seesharper _"There's no way to avoid a nested iteration of each of the arrays."_ that is not correct. Ignoring the values we have a finite set unique indexes, where we can use addition to determine the the resulting permutations. Though do agree that brute-force can solve the problem, by first doing the math by hand and then converting the hand written math to code. – guest271314 Jan 22 '18 at 03:46
  • @guest271314 I do get my expected results, i just know that doing what I want to do the way I'm doing it gives me an O^n(4) (i think?) My question has been updated – Naji Jan 22 '18 at 03:54
  • @KenWhite I'm sorry for the misunderstanding. I didn't mean to ask for any "code monkey" to "churn" out anything for me. If you look at my history on here, I've never asked for advice such as this on StackOverflow, only questions to things I've spent hours or days trying to figure out. This is my first time asking a question in this manner and now I know the full extent of how StackOverflow works and will be sure to approach situations like this differently... – Naji Jan 22 '18 at 03:58
  • @JaromandaX please see my previous comment to Ken. I appreciate you clarifying the environment of StackOverflow to me and I will be sure to include all attempts at problem solving in my original question – Naji Jan 22 '18 at 03:59
  • @Naji If the actual inquiry concerns the efficiency of the procedure, then the current benchmarks of the approaches that you have tried should be included at the Question, and precisely how efficiency is defined and evaluated to determine if the requirement is being met. See also [How to improve efficiency of algorithm which generates next lexicographic permutation?](https://stackoverflow.com/questions/43290467/how-to-improve-efficiency-of-algorithm-which-generates-next-lexicographic-permut?) – guest271314 Jan 22 '18 at 04:00
  • @guest271314 I see. I'm sorry but I'm very new to computer science and computer programming in general so I am not familiar with establishing benchmarks or defining standards for efficiency. The only understanding I have of algorithmic efficiency is the general concept of Big O notation and (generally) how it can be calculated/deduced, and I was taught that nested for-loops are to be avoided at all costs. So I guess if that is the level of seniority I need to be at to get help with this subject matter, I can delete the question – Naji Jan 22 '18 at 04:04
  • @Naji Do not let "downvote"s or this users' perspective as to the inquiry deter you if you do not have the answer that you are trying to get. Have minimal experience with Big O notation here; have used basic tools to try to determine how long the procedure takes to complete as a mechanism for measuring whether the current process completes in less time than the previous process. – guest271314 Jan 22 '18 at 04:08
  • @Naji - "nested for loops are to be avoided at all costs" is a piece of dogma. Dogma is about the only thing that should be avoided "at all costs". There is nothing wrong with nested for loops if they are the simplest solution. There _may_ be a more efficient solution, or there may not. For this case I doubt you'll find anything that benchmarks significantly faster than brute force, though I may be wrong! Functional formulations using accumulators etc may avoid the appearance of nested for loops, but underneath are doing exactly the same thing. – see sharper Jan 22 '18 at 04:11
  • @guest271314 thank you for the encouragement. Thanks to StackOverflow I've gotten through a lot of headaches so I really do appreciate this community. I guess in the meantime I will stick with what I have and try to look in to general methods of efficiency and calculating computing power/runtime etc :) – Naji Jan 22 '18 at 04:13
  • @seesharper what you're saying makes sense. It's true, I've found that a lot of computer scientists really enjoying solving puzzles better than the next person, so sometimes the advice I get as a beginner involves a lot of bias and dogmas. But I guess I'm going to stick with what I have for now until I gain some more experience and can think of a more creative solution down the line (if there is one) :) – Naji Jan 22 '18 at 04:14
  • @Naji FWIW [Permutations without recursive function call](https://stackoverflow.com/questions/34013675/permutations-without-recursive-function-call) includes several links relevant to permutations, and the accepted Answer is the most efficient permutations algorithm that have yet encountered, so far. – guest271314 Jan 22 '18 at 04:18
  • @guest271314 I think your refutation of my remark is a little pedantic. It's not _strictly_ true that there's no way to avoid nested iteration, but my point is really that each element in each array must be accessed, and therefore there's not much efficiency to be gained, as there's no redundancy in the data to exploit. – see sharper Jan 22 '18 at 04:18
  • @guest271314 amazing, thank you so much for the resource! :) I'm not asking you to, but if you happen to remember this thread one day while you're reading about something relevant to this subject, feel free to link it because I would love to learn as much as possible :) – Naji Jan 22 '18 at 04:21
  • 1
    @seesharper We ignore values at the outset. If we ignore that there are distinct "arrays" and recognize only the indexes of the sets, we can reduce the 4 or N arrays to a single set. From there we can rearrange the indexes without duplication using addition by viewing the "indexes" of the "arrays" as whole numbers, which begin at a given number and must end at a specific number due to the set being finite. We could take that a step further and calculate every unique particle in the universe at any given point in time using any particle, as the declination slope is equal to the incline. – guest271314 Jan 22 '18 at 04:21
  • 1
    @seesharper More importantly, once we recognize that the final result is a whole number, and that the declination slope of the graph is equal to the inclination slope of the graph as to the differences between the points on the graph, we only need to calculate the first half + 1 of the total permutations `(k / 2) + 1`, where `k` the whole number representation of the last lexicographic permutation indexes; then use the first half of calculations to derive the declination slope of the remainder half - 1 permutations; using addition. Until create a method to do so without addition and exclusion. – guest271314 Jan 22 '18 at 04:39
  • @guest271314 You lost me when you got to calculating every unique particle on the universe... – see sharper Jan 22 '18 at 22:55

2 Answers2

4

Use Array#product, as @sagarpandya suggests.

def get_em_all(a, *arr)
  a.product(*arr)
end
get_em_all(a, b, c, d)
  # => [[1, "A", "J", "v"], [1, "A", "J", "w"], [1, "A", "J", "x"], [1, "A", "J", "y"],
  #     [1, "A", "J", "z"], [1, "A", "K", "v"], [1, "A", "K", "w"], [1, "A", "K", "x"],
  #     ...
  #     [5, "E", "N", "w"], [5, "E", "N", "x"], [5, "E", "N", "y"], [5, "E", "N", "z"]]

get_em_all(a, b, c, d).size
  #=> 625 (= 5**4)

Note that if the arguments of get_em_all are changed to something else--8 3-element arrays, for example----no change is required to the method.

Objects, such as arrays, do not know the variable or variables that hold them. Consider, for example,

a = [1,2,3]
b = a
  #=> [1, 2, 3]
a.object_id
  #=> 4303360
b.object_id
  #=> 4303360

Both the variable a and the variable b old the same object, the array [1,2,3].

Therefore, to obtain the array of hashes you want you would have to construct it at compile time with keys that are literals, hardwired to the four arrays a, b, c, and k. Moreover, there's no reason to use names of variables as the hash's keys. That would be bad bad programming practice on several levels.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
3

If you want all the possible combinations, there's no alternative other than iterating through each of the elements for all arrays.

Creating hashes is not difficult either.

Try this.

a = [1, 2, 3, 4, 5]
b = ['A', 'B', 'C', 'D', 'E']
c = ['J', 'K', 'L', 'M', 'N']
d = ['v', 'w', 'x', 'y', 'z']

result = []

a.each do |a_elem|
  b.each do |b_elem|
    c.each do |c_elem|
      d.each do |d_elem|
        result << {a: a_elem, b: b_elem, c: c_elem, d: d_elem}
      end
    end
  end
end

puts "#{result}"

I believe this is what you are looking for.

Nabin Paudyal
  • 1,591
  • 8
  • 14
  • It is, and this is similar to the manner in which I was going to create the array of objects before, except I had turned `sub_array` in to an empty object `{}` and was pushing that to my `master_array` instead. your way is written much more elegantly and I appreciate you taking the time – Naji Jan 22 '18 at 04:17
  • You can write `p result` to print the array. – Sagar Pandya Jan 22 '18 at 04:35
  • The Ruby monks gave us `Array#product` so we wouldn't have to do what you've done, and also so that we could change the input (remove `d` or add ` e = [`to", 'be', 'or', 'not', 'tobe']`, for example). without changing the method. (Sorry about `'tobe'``, but it had to be five words.) – Cary Swoveland Jan 22 '18 at 06:13