split the contents of the array into two other arrays - ruby

Simple example but I want to understand how it is done so I can apply it else where I have a main array with 6 elements. I want to take 3 of the elements from the main array and put it in a array and then take the other 3 from main array and put them in b array. I will use this to apply it to dealing cards to two players
main = [1, 2, 3, 4, 5, 6]
a = [ ]
b = [ ]

main = [1, 2, 3, 4, 5, 6]
#=> [1, 2, 3, 4, 5, 6]
main.first(3)
#=> [1, 2, 3]
main.last(3)
#=> [4, 5, 6]

a = [1, 2, 3, 4, 5, 6]
#=> [1, 2, 3, 4, 5, 6]
b = a.take(3)
#=> [1, 2, 3]
c = a.drop(3)
#=> [4, 5, 6]

All may have given the right answer, But as I understood from your question (I will use this to apply it to dealing cards to two players) When you dealing cards, as you deal cards to player main array should remove that element from self array to overcome Redundancy Problem (duplication). When you deal the all cards main array must be empty.
For this solution have a look at Array#shift
> main = [1,2,3,4,5,6] # I have 6 cards on my hand before dealing cards to players
=> [1, 2, 3, 4, 5, 6]
> a = main.shift(3) # given 3 cards to Player a
=> [1, 2, 3]
> b = main.shift(3) # given 3 cards to Player b
=> [4, 5, 6]
> main # after dealing all cards to two players I should not have any card on my hand
=> []

You have many ways to do the same thing in Ruby. Splitting arrays isn't an exception. Many answers (and comments) told you some of the ways to do that. If your program is dealing cards, you won't stop there. First, you'll probably have more than 6 cards. Second, you're probably going to have more than 2 players. Let's say the cards are C and the players are P. You need to write a method that, no matter how many Cs or Ps there are, the method is going to give each Player an equal number of Ccards (or return an error if it can't give it an equal number of cards). So for 6 cards and 2 players, it will give 3 cards each. For 12 cards and 3 players, 4 cards each. For 3 cards and 2 players, it's going to produce an error because the cards can't be evenly split:
def split_cards_evenly_between_players(cards, players)
if cards.size % players != 0
raise 'Cannot split evenly!'
else
groups_to_split_into = cards.size / players
cards.each_slice(groups_to_split_into).to_a
end
end
Let's go through the code. If the cards can't be evenly split between players, then the remainder by dividing them won't be 0 (6 cards / 3 players = remainder 0. 7 cards / 3 players = remainder 1). That's what line 2 checks. If the cards CAN be split, then we first find the groups to split into (which is dividing the number of cards by the number of players). Then we just split the array into that many groups with Enumerable#each_slice. Finally, since this doesn't produce an array, we need .to_a to convert it. The return value in Ruby is always the value of the last expression executed. The only expression in this method is the if/then expression which also returns the value of the last expression executed (which is the line where each_slice is). Let's try it out:
p split_cards_evenly_between_players([1,2,3,4,5,6,7,8,9,10,11,12],2) #=> [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]]
p split_cards_evenly_between_players([4,5,1,2,5,3], 3) #=> [[4, 5], [1, 2], [5, 3]]
p split_cards_evenly_between_players([1,2,3],2) #=> Error: Cannot split evenly!
The nice thing about Ruby is its simple syntax and the fact it tries to get out of your way while solving a problem so you can focus more on the actual problem than the code.

Related

Why does my algorithm solution fail validation?

Here is a task i got:
Cards are laid out on the table in a row, each card has a natural number written on it. In one move, it is allowed to take a card either from the left or from the right end of the row. In total, you can make k moves. The final score is equal to the sum of the numbers on the selected cards. Determine what is the maximum score you can get at the end of the game.
Here`s my code:
def card_counter(arr, k):
if len(arr) == k:
return sum(arr)
rang = len(arr) // 2
left = arr[:rang]
right = list(reversed(arr[rang:]))
c = 0
for _ in range(k):
min_arr = left if sum(left) >= sum(
right) and len(left) > 0 else right
c += min_arr.pop(0)
return c
if __name__ == '__main__':
assert card_counter([1, 2, 3, 4, 5], 5) == 15
assert card_counter([0, 0, 0], 1) == 0
assert card_counter([150], 1) == 150
This code works on all variants that I have come up with, including extreme cases. But the system does not accept this option, automatic tests do not pass. Where can there be a mistake?
I cannot comment on the algorithm you implemented as you did not state it in non-algorithm terms and I am not familiar with the language you are using (which I am guessing is Python). I will present a simple solution written in Ruby, hoping that the description I give will make it understood by readers who do not know Ruby.
Suppose
deck = [1, 2, 5, 7, 1, 4, 6, 3]
nbr_moves = 4
ds = deck.size
#=> 8
After removing nbr_moves from the ends,
m = ds - nbr_moves
#=> 4
consecutive cards will remain. In Ruby we could write
best = (0..ds-1).each_cons(m).max_by { |arr| deck.values_at(*arr).sum }
#=> [3, 4, 5, 6]
to obtain the indices of deck, for which the sum of the associated values is maximum:
deck.values_at(*best).sum
#=> 18
where
deck.values_at(*best)
#=> [7, 1, 4, 6]
In view of the value of best ([3, 4, 5, 6]), we need to remove left = best.first #=> 3 elements from the left and nbr_moves - left #=> 1 element from the right. The order of the removals is not relevant.
Note that
enum = (0..ds-1).each_cons(m)
#=> #<Enumerator: 0..7:each_cons(4)>
returns an enumerator. We can convert this enumerator to an array to see the values it will generate.
enum.to_a
#=> [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]
When, for example,
arr = [2, 3, 4, 5]
then
a = deck.values_at(*arr)
#=> [5, 7, 1, 4]
a.sum
#=> 17
Note that, having computed, for example,
t = [deck[i], deck[i+1],..., deck[j]].sum
the sum of
[deck[i+1], deck[i+2],..., deck[j+1]]
is seen to equal
t - deck[i] + deck[j+1]
This suggests a more efficient way to perform the calculations when m is large.

Ruby: Divide array into 2 arrays with the closest possible average

Background: I'm working on a "matchmaking system" for a small multiplayer video game side project. Every player has a rank from 0-10, every team has 4 players. I'm trying to find a good way to balance out the teams so that the average rank of both of them is as close as possible and the match is as fair as possible.
My current, flawed approach looks like this:
def create_teams(players)
teams = Hash.new{|hash, team| hash[team] = []}
players.sort_by(&:rank).each_slice(2) do |slice|
teams[:team1] << slice[0]
teams[:team2] << slice[1]
end
teams
end
This works decently well if the ranks are already pretty similar but it's not a proper solution to this problem.
For example, it fails in a situation like this:
require "ostruct"
class Array
def avg
sum.fdiv(size)
end
end
dummy_players = [9, 5, 5, 3, 3, 3, 2, 0].map{|rank| OpenStruct.new(rank: rank)}
teams = create_teams(dummy_players)
teams.each do |team, players|
ranks = players.map(&:rank)
puts "#{team} - ranks: #{ranks.inspect}, avg: #{ranks.avg}"
end
This results in pretty unfair teams:
team1 - ranks: [0, 3, 3, 5], avg: 2.75
team2 - ranks: [2, 3, 5, 9], avg: 4.75
Instead, I'd like the teams in this situation to be like this:
team1 - ranks: [0, 3, 3, 9], avg: 3.75
team2 - ranks: [2, 3, 5, 5], avg: 3.75
If there are n players, where n is an even number, there are
C(n) = n!/((n/2)!(n/2)!)
ways to partition the n players into two teams of n/2 players, where n! equals n-facorial. This is often expressed as the number of ways to choosing n/2 items from a collection of n items.
To obtain the partition that has a mimimum absolute difference in total ranks (and hence, in mean ranks), one would have to enumerate all C(n) partitions. If n = 8, as in this example, C(8) = 70 (see, for example, this online calculator). If, however, n = 16, then C(16) = 12,870 and C(32) = 601,080,390. This gives you an idea of how small n must be in order perform a complete enumeration.
If n is too large to enumerate all combinations you must resort to using a heuristic, or a subjective rule for partitioning the array of ranks. Here are two possibilities:
assign the highest rank element ("rank 1") to team A, assign elements with ranks 2 and 3 to team B, assign elements with ranks 4 and 5 to team A, and so on.
assign elements with ranks 1 and n to team A, elements with ranks 2 and n-1 to team B, and so on.
The trouble with heuristics is evaluating their effectiveness. For this problem, for every heuristic you devise there is an array of ranks for which the heuristic's performance is abysmal. If you know the universe of possible arrays of ranks and have a way of drawing unbiased samples you can evaluate the heuristic statistically. That generally is not possible, however.
Here is how you could examine all partitions. Suppose:
ranks = [3, 3, 0, 2, 5, 9, 3, 5]
Then we may perform the following calculations.
indices = ranks.size.times.to_a
#=> [0, 1, 2, 3, 4, 5, 6, 7]
team_a = indices.combination(ranks.size/2).min_by do |combo|
team_b = indices - combo
(combo.sum { |i| ranks[i] } - team_b.sum { |i| ranks[i] }).abs
end
#=> [0, 1, 2, 5]
team_b = indices - team_a
#=> [3, 4, 6, 7]
See Array#combination and Enumerable#min_by.
We see that team A players have ranks:
arr = ranks.values_at(*team_a)
#=> [3, 3, 0, 9]
and the sum of those ranks is:
arr.sum
#=> 15
Similarly, for team B:
arr = ranks.values_at(*team_b)
#=> [2, 5, 3, 5]
arr.sum
#=> 15
See Array#values_at.

Combine lists to the least possible amount of 2-dimensional lists

Sorry for the bad description in the title.
Consider a 2-dimensional list such as this:
list = [
[1, 2],
[2, 3],
[3, 4]
]
If I were to extract all possible "vertical" combinations of this list, for a total of 2*2*2=8 combinations, they would be the following sequences:
1, 2, 3
2, 2, 3
1, 3, 3
2, 3, 3
1, 2, 4
2, 2, 4
1, 3, 4
2, 3, 4
Now, let's say I remove some of these sequences. Let's say I only want to keep sequences which have either the number 2 in position #1 OR number 4 in position #3. Then I would be left with these sequences:
2, 2, 3
2, 3, 3
1, 2, 4
2, 2, 4
1, 3, 4
2, 3, 4
The problem
I would like to re-combine these remaining sequences to the least possible amount of 2-dimensional lists needed to contain all sequences but no less or no more.
By doing so, the resulting 2-dimensional lists in this particular example would be:
list_1 = [
[2],
[2, 3],
[3, 4]
]
list_2 = [
[1],
[2, 3],
[4]
]
In this particular case, the resulting lists can be thought out. But how would I go about if there were thousands of sequences yielding hundereds of 2-dimensional lists? I have been trying to come up with a good algorithm for two weeks now, but I am getting nowhere near a satisfying result.
Divide et impera, or divide and conquer. If we have a logical expression, stating that the value at position x should be a or the value at position y should be b, then we have 3 cases:
a is the value at position x and b is the value at position y
a is the value at position x and b is not the value at position y
a is not the value at position x and b is the value at position y
So, first you generate all your scenarios, you know now that you have 3 scenarios.
Then, you effectively separate your cases and handle all of them in a sub-routine as they were your main tasks. The philosophy behind divide et imera is to reduce your complex problem into several similar, but less complex problems, until you reach triviality.

Convert an array in ruby into an output stream

I have an array [2, 4, 6, 8, 3], i need to convert it into an output stream as below:
2 4 6 8 3
Converting into string and chopping the commas and quotes is not helping as it always prints as "2 4 6 8 3" if it is a string.
This is the input given:
5
2 4 6 8 3
This is the code i wrote
def insertionSort( ar)
key = ar.last
(ar.size-2).downto(0){
|x|
if(key < ar[x])
ar[x+1] = ar[x]
p ar
else
ar[x+1] = key
p ar
break
end
}
end
# Tail starts here
count = gets.to_i
ar = gets.strip.split.map {|i| i.to_i}
insertionSort( ar )
My Output:
[2, 4, 6, 8, 8]
[2, 4, 6, 6, 8]
[2, 4, 4, 6, 8]
[2, 3, 4, 6, 8]
Expected Outuput:
2 4 6 8 8
2 4 6 6 8
2 4 4 6 8
2 3 4 6 8
Test Result:
Fail
Your question isn't at all clear, but, maybe this is what you want:
ary = [2, 4, 6, 8, 3]
ary.join(' ') # => "2 4 6 8 3"
ary * ' ' # => "2 4 6 8 3"
Perhaps you don't understand how to loop?
ary = [2, 4, 6, 8, 3]
5.times do
puts ary.join(' ')
end
# >> 2 4 6 8 3
# >> 2 4 6 8 3
# >> 2 4 6 8 3
# >> 2 4 6 8 3
# >> 2 4 6 8 3
Or maybe you don't understand how command-line apps read STDIN?
Dealing with STDIN is useful when writing pipes: Chaining one small specialized application to another, and letting them collectively do a big task is the basic premise for *nix systems. Monolithic apps that try to do everything are a major PITA to write/maintain and use.
If you want to read a single line of input, either from STDIN or the keyboard, gets is good. If you want to read a series of lines, look at Ruby's ARGF class, and become very familiar with how STDIN and $stdin work.
Writing a Ruby command-line script is easy, but, just like doing it in Perl, Python or C, you have to be aware how the incoming data is accessed, what type of data it is (always a string), and how it's structured: characters terminated by a new-line ("\n") or carriage-return+new-line ("\r\n").
Perhaps you don't understand how to_i works?
"2 4 6 8 3".to_i # => 2
"24683".to_i # => 24683
"2_4_6_8_3".to_i # => 24683
to_i reads the string from the first character and continues until it finds a non-digit. So, in the above examples, 2 is the first digit in the first string, followed by a space. The space is a non-digit so to_i stops processing and only returns 2. In the second example, there are no spaces, so to_i processes the entire string and returns it as a single value. In the third, because Ruby, like some other languages, accepts _ as a part of a numeric string, to_i returns the full value again. _ is used to mark the comma positions in values, like 1_000_000.
As you write more code, take the time to write it clearly and cleanly. You want code that reduces the visual noise and makes it easy to take into your brain. Ruby makes it easy to write clean and expressive code that is easy to understand, but bad coding style can reduce Ruby code to unreadable quickly, especially to those of us who are used to seeing it written in an idiomatic style.
This isn't an attempt to fix your algorithm, it's just to show how you should style your code:
def insertion_sort(ar)
key = ar.last
(ar.size - 2).downto(0) { |x|
if (key < ar[x])
ar[x + 1] = ar[x]
p ar
else
ar[x + 1] = key
p ar
break
end
}
end
# Tail starts here
count = gets.to_i
ar = gets.strip.split.map { |i| i.to_i }
insertion_sort(ar)
Methods are always written in snake_case, never CamelCase.
Use whitespace; It gives your eyes and brain logical breaks that help define what is going on. Operators and control structures benefit from having whitespace before and after, and above and below.
Use spaces to indent, with tab-stops set to 2-spaces. This is the Ruby standard. Why those? Consistency as people move code between different editors; If you're working in a professional coding house you'll probably find a lot more rigid coding standards in place.
> a = [1, 2, 3, 4]
> puts "[#{a.join(', ')}]"
=> [1, 2, 3, 4]
Does not work on multi-dimensional arrays, or arrays within arrays.
> a = [1, 2, [3, 4, 5, 6], [7, 8, 9]]
> puts "[#{a.join(', ')}]"
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
But, if you do this, it should work for multi-dimensional arrays:
Example 1:
> a = [1, 2, [3, 4, 5, 6], [7, 8, 9]]
> a.each do |sub_a|
> puts "[#{a.join(', ')}]"
> end
=> [1, 2, [3, 4, 5, 6], [7, 8, 9]]
Example 2:
> a = [1, [2, [3, 4, [5, 6, 7, 8], 9, 0]], 'x', 'y', 'z']
> a.each do |sub_a|
> puts "[#{a.join(', ')}]"
> end
=> [1, [2, [3, 4, [5, 6, 7, 8], 9, 0]], "x", "y", "z"]
After reading the HackerRank "Insertion Point" question you referenced, the input appears to be coming from stdin. If your code includes
s = gets
it will wait for you to enter a string. Suppose you enter 1 2 3 4 (no quotes). Then s will hold "1 2 3 4\n".
If you want to convert this to an array:
a = s.split # => ["1","2","3","4"]
If you want the elements of a to be integers, rather than strings:
a.map! {|e| e.to_i} # => [1,2,3,4]
which (since Ruby version 1.9) can also be written:
a.map!(&:to_i) # => [1,2,3,4]
The 'Ruby way' would be to chain these operations:
a = gets.split.map(&:to_i) # => [1,2,3,4]
Note that we don't need ! with map now.
If you want this array to be a row i of some (existing array) b
b[i] = a

Sorting arrays, and selecting lowest numbers?

I have created several arrays, containing multiple integers. Now i want the integers to be sorted, lowest first. Say for instance, i have this in an array: 6,6,1,2,4,4, i want it to be sorted: 1,2,4,4,6,6. Also, is there anyway i can make ruby recognize the 4 lowest values, and display them somehow? I have tried to mess around with .show, but since im quite new to programming i'm rather confused by the results i receive.
did you try this?
a = [6,6,1,2,4,4]
p a.sort
#=> [1, 2, 4, 4, 6, 6]
sort will sort in ascending order.
if you need them sorted in descending order, use sort with a block:
p a.sort {|a,b| b <=> a}
#=> [6, 6, 4, 4, 2, 1]
UPDATE: not sure how i missed the part about lowest values ...
thank you #Mladen
a.sort.take(4)
#=> [1, 2, 4, 4]

Resources