How do i append another list within list comprehension - for-comprehension

I am trying to find out unique elements and avoid duplicates , between the lists (using list comprehension)
`a = [10 , 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,9]`
`b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]`
dup_list = []
This works , but with duplicates
`final_list = [uniq for uniq in a if a not in dup_list if uniq in b ]`
when i try to append the my dup_list in the last line of the comprehension statement it says invalid syntax
i.e this doesn't work.
"final_list = [uniq for uniq in a if a not in dup_list if uniq in b dup_list.append(uniq) "
I am a newbie in python so apologize for any missed out basic facts .

a = [10, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 9]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
nodupes = sorted([item for item in a if item not in b] +
[item for item in b if item not in a])
That yields [4, 6, 7, 11, 12, 21, 34, 55, 89]
Which is the same answer I get using sets:
seta = set(a)
setb = set(b)
nodupes = sorted(list(seta ^ setb))

Related

Spliting tables into 9's

I would like to know how can I split my table into subtables of 9's.
Example:
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }
Code shall return:
{ {1, 2, 3, 4, 5, 6, 7, 8, 9}, {10, 11, 12, 13, 14, 15, 16, 17, 18}, { 19, 20} }
How do you think is this done?
Your code seems over complicated. The task is to create a subtable every 9 elements. The code below does that:
a={ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }
b={}
j=0
k=9
for i=1,#a do
if k==9 then j=j+1; b[j]={}; k=0 end
k=k+1
b[j][k]=a[i]
end
Here, j tracks the number of subtables created and k tracks the number of elements added to a subtable. When k becomes 9, a new subtable is created. k starts at 9 to signal that.

Remove multiple ranges of values from array

a1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
a2 = [2..4, 8..11, 16..17]
Removing one range of values from an array can be done like this:
[1, 2, 3, 4, 5, 6, 7, 8, 9].slice!(2..5)
Iterating over the ranges and apply the same as above (a2.each { |range| a1.slice!(range) }) isn't perfect though. The ranges overlap sometimes and thus destroy the referencing index for the other ranges.
So, any suggestions on how to remove the ranges in a2 from a1 in the most efficient way?
a1 is normally [*0..10080] long. a2 has about 30 ranges, each containing hundreds of values.
If the result of the first operation impacts the second you're either going to have to track the resulting offset implications, which can get crazy complicated, or simply go about doing the reverse operation and instead flag which you want or don't want using the ranges:
require 'set'
a1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
a2 = [2..4, 8..11, 16..17]
# Convert the ranges to a set of index values to remove
reject = Set.new(a2.flat_map(&:to_a))
# Using value/index pairs, accumulate those values which are
# not being excluded by their index.
a1.each_with_index.each_with_object([ ]) do |(v, i), a|
a << v unless (reject.include?(i))
end
# => [0, 1, 5, 6, 7, 12, 13, 14, 15, 18, 19, 20]
[-1, *a2.flat_map(&:minmax), a1.length].each_slice(2).flat_map{|i,j| a1[i+1...j]}
# => [0, 1, 5, 6, 7, 12, 13, 14, 15, 18, 19, 20]
I'm not sure this is the least naive solution, but it seems simple to convert your ranges into arrays so you're dealing with like-for-like:
a2.each{ |a| a1 = a1 - a.to_a }
a1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
a2 = [2..4, 8..11, 16..17]
a1 - a2.flat_map(&:to_a)

ruby/rails array all elements between two indices

I have an array like this: [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
What's the simplest way to return each item in the array from position 6 until 0 where the resulting array looks like: [1,2,3,4,5,6,7]
This positions in the array can be dynamic, for example passing in 4 and 9 should return [11,12,1,2,3,4]
I'm wondering if there's a method that accomplishes this in Rails api.
Thanks in advance
EDIT
Let's assume that no negative numbers, so doing array[2..-2] wont work.
Array#splice almost works for this, but if the second position is less than the first, it returns nil.
def foo a, min, max
a.rotate(min).first((max - min) % a.length + 1)
end
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
foo(a, 6, 0) # => [1, 2, 3, 4, 5, 6, 7]
foo(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
class Array
def get_sub_array(start,last)
(start > last) ? (self[start..-1] + self[0..last]) : self[start..last]
end
end
Then
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
a.get_sub_array(6,0)
#[1, 2, 3, 4, 5, 6, 7]
Or if you don't want to monkey patch
You could have a method like
def get_sub_array(array, start,last)
(start > last) ? (array[start..-1] + array[0..last]) : array[start..last]
end
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
get_sub_array(a,6,0)
#[1, 2, 3, 4, 5, 6, 7]
def some_function(some_array,start_val=6, end_val=0)
if end_val > start_val
some_array[start_val,(end_val - start_val)]
else
(some_array[start_val, some_array.size] << some_array[0, (end_val)]).flatten
end
end
You can use ternary operator to make it one liner too:
def some_function(some_array,start_val=6, end_val=0)
end_val > start_val ? some_array[start_val,(end_val - start_val)] : (some_array[start_val, some_array.size] << some_array[0, (end_val)]).flatten
end
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
some_function(a) # => [1, 2, 3, 4, 5, 6, 7]
some_function(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
min=6
max=0
arr = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
result = []
if max<min
result << arr[min..arr.length]
result << arr[0..max]
else
result << arr[min..max]
end
A couple more ways (my preference being for #1).
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
#1
def foo a, min, max
as = a.size
max += as if max < min
(min..max).map { |i| a[i%as] }
end
foo(a, 6, 0) # => [ 1, 2, 3, 4, 5, 6, 7]
foo(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
#2
def foo a, min, max
max += a.size if max < min
e = a.cycle
min.times { e.next }
(max-min+1).times.map { e.next }
end
foo(a, 6, 0) # => [ 1, 2, 3, 4, 5, 6, 7]
foo(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
def foo a, s, e
a = e < s ? (a[s,a.size] << a[0..e]).flatten : a[s..e]
end
a = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
a = foo(a, 6, 0) # => [1, 2, 3, 4, 5, 6, 7]
a = foo(a, 4, 9) # => [11, 12, 1, 2, 3, 4]
myArray = [7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
myArray[6..-1] returns [1, 2, 3, 4, 5, 6]
myArray[4..9] returns [11,12,1,2,3,4]

ruby array (enumerable) method to select and reject into 2 arrays in 1 operation

# this code works
list = (0..20).to_a
# => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
odd = list.select { |x| x.odd? }
# => [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
list.reject! { |x| x.odd? }
# => [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# but can i emulate this type of functionality with an enumerable method?
set = [1,5,10]
# => [1, 5, 10]
one, five, ten = set
# => [1, 5, 10]
one
# => 1
five
# => 5
ten
# => 10
# ------------------------------------------------
# method I am looking for ?
list = (0..20).to_a
odd, even = list.select_with_reject { |x| x.odd? }
# put the matching items into the first variable
# and the non-matching into the second
Sure, you can do:
odd, even = list.partition &:odd?
odd = []
even = []
list = [1..20]
list.each {|x| x.odd? ? odd << x : even << x }
As pguardiario said, the partition method is the most direct way. You could also use Set#divide:
require 'set'
list = (1..10).to_a
odd, even = Set.new(list).divide(&:odd?).to_a.map{|x| x.to_a}
You could try below:
odd,even = (0..20).group_by(&:odd?).values
p odd,even
Output:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

Grails sorting asList() , sort()

I want to sort the result here my code:
def games = Game.withCriteria() {
eq('season', currentSeason)
eq('competition', competition)
round {
ge('roundNr', startRound.roundNr)
}
or {
round {
le('roundNr', currentRound.roundNr)
}
gt('state', Game.STATE_NOT_STARTED)
}
order 'date', 'asc'
}
def sortGames = games.asList().sort(games.round.sorting)
The query works fine, i want to sort them.
Error:
Error 500: Executing action [recalcCompetitionTable] of controller [at.ligaportal.CompetitionController] caused exception: groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.sort() is applicable for argument types: (java.util.ArrayList) values: [[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 2, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16]] Possible solutions: sort(), sort(java.util.Comparator), sort(groovy.lang.Closure), wait(), size(), size()
Servlet: grails
URI: /ligaportal/grails/competition/recalcCompetitionTable.dispatch
Exception Message: No signature of method: java.util.ArrayList.sort() is applicable for argument types: (java.util.ArrayList) values: [[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 2, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16]] Possible solutions: sort(), sort(java.util.Comparator), sort(groovy.lang.Closure), wait(), size(), size()
Caused by: No signature of method: java.util.ArrayList.sort() is applicable for argument types: (java.util.ArrayList) values: [[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 2, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16]] Possible solutions: sort(), sort(java.util.Comparator), sort(groovy.lang.Closure), wait(), size(), size()
Class: ApiAuthenticationFilter
At Line: [77]
where is my Problem?
I got the Games via withCriteria() method, sort by date.
And all games have rounds , and now i want to sort them by the sorting of the rounds.
5 Games have 1 Round and alle Games have dates.
Round 1 = 18.09.2012 - 25.09.2012 (5 Games)
Round 2 = 26.09.2012 - 31.09.2012 (4 Games) and one Game plays later
5.11.2012
Round 3 = 1.10.2012 - 7.10.2013
And my problem is, i sum up the round with a each and previous round.
Roudn 1 = 3,3,3,1,1 Points
Round 2 = 6,4,4,2,1 Points -> 1 Games later
Round 3 = 9,7,7,4,3 Pounts
Round 2 = 6,4,4,4,1 (after game)
Round 4 = here i cant go back to round 4 -> the one game is lost!
And now i want to order the games via game.round.sorting
This is my problem.
Thank you!
The Solution
def bySorting = new Comparator() {
int compare(a,b) { a.round.sorting <=> b.round.sorting }
}
games.sort(bySorting)
You don't need to call sort()on games due to the result of your criteria is already sorted.
Instead sorting by date : order 'date', 'asc' you could add your desired property here.
If you really need to sort the result you have to pass an Comparator or a Closure to sort():
def sortGames = games.asList().sort{it.round.sorting}
You should provide some more information. Looks like sorting is an ArrayList - how should the games be sorted?
You should be able to sort by round as part of the initial database query by using createAlias in your criteria:
def games = Game.withCriteria() {
createAlias('round', 'rnd')
eq('season', currentSeason)
eq('competition', competition)
ge('rnd.roundNr', startRound.roundNr)
or {
le('rnd.roundNr', currentRound.roundNr)
gt('state', Game.STATE_NOT_STARTED)
}
order 'rnd.sorting', 'asc'
}
This way you don't need to do any sorting of the returned list in Groovy.
However, if you do want to sort an existing list of games by their round.sorting value then you almost had the right syntax. What you actually need is:
def sortGames = games.sort { it.round.sorting }
The Groovy sort method expects a closure that returns the sort key, whereas your attempt was passing a list of all the sort keys for all the games.
From your code it is not clear what games.round.sorting does.
But have a look at the following links to learn more about sorting lists in groovy:
Custom list sorting
Groovy OrderBy
Or google for Groovy Comparator to find other examples and descriptions.

Resources