I am using a module that is part of a commercial software API. The good news is there is a python module - the bad news is that its pretty unpythonic.
To iterate over rows, the follwoing syntax is used:
cursor = gp.getcursor(table)
row = cursor.next()
while row:
#do something with row
row = cursor.next()
What is the most pythonic way to deal with this situation? I have considered creating a first class function/generator and wrapping calls to a for loop in it:
def cursor_iterator(cursor):
row = cursor.next()
while row:
yield row
row = cursor.next()
[...]
cursor = gp.getcursor(table)
for row in cursor_iterator(cursor):
# do something with row
This is an improvement, but feels a little clumsy. Is there a more pythonic approach? Should I create a wrapper class around the table type?
Assuming that one of Next and next is a typo and they're both the same, you can use the not-so-well-known variant of the built-in iter function:
for row in iter(cursor.next, None):
<do something>
You could create a custom wrapper like:
class Table(object):
def __init__(self, gp, table):
self.gp = gp
self.table = table
self.cursor = None
def __iter__(self):
self.cursor = self.gp.getcursor(self.table)
return self
def next(self):
n = self.cursor.next()
if not n:
raise StopIteration()
return n
and then:
for row in Table(gp, table)
See also: Iterator Types
The best way is to use a Python iterator interface around the table object, imho:
class Table(object):
def __init__(self, table):
self.table = table
def rows(self):
cursor = gp.get_cursor(self.table)
row = cursor.Next()
while row:
yield row
row = cursor.next()
Now you just call:
my_table = Table(t)
for row in my_table.rows():
# do stuff with row
It's very readable, in my opinion.
Related
I'm using a tool for finding code smells in code called reek and I have a problem with one called Control Parameter
def place_ship(ship, start_position, orientation)
#row = start_position[:row]
#column = start_position[:column]
ship.length.times do
if orientation == :vertical
vertical_place_ship(row,column,ship)
else
horizontal_place_ship(row,column,ship)
end
end
end
def vertical_place_ship(row,column,ship)
self.grid[row][column].ship = ship
self.grid[row][column].status = :occupied
#row += 1
end
def horizontal_place_ship(row,column,ship)
self.grid[row][column].ship = ship
self.grid[row][column].status = :occupied
#column += 1
end
warning's content: [
55]:ControlParameter: Board#place_ship is controlled by argument 'orientation
How do I fix this?
'Orientation' is a flag value in place_ship method. Value of 'orientation' is not changing as the code executes. So no need to check it 'ship.length' times.
place_ship has only conditional logic and nothing else. This is unnecessary and the conditional logic can reside outside. You are passing in a flag, that tells the method what path to choose, conditionally. This is the Conditional Coupling smell. Generally do not pass in a conditional parameter to a method. Have 2 different methods for the 2 choices and name them aptly.
You already have aptly named vertical_place_ship and horizontal_place_ship methods. You can refactor it like this.
def <method_that_calls_place_ship>
// other code
if orientation == :vertical
vertical_place_ship(ship, start_position)
else
horizontal_place_ship(ship, start_position)
end
// more code
end
def vertical_place_ship(ship, start_position)
row = start_position[:row]
column = start_position[:column]
ship.length.times do
self.grid[row][column].ship = ship
self.grid[row][column].status = :occupied
row += 1
end
end
Similarly for horizontal_place_ship method.
Regardless of the tool feedback, looking at your code, the only line that differ between the horizontal & vertical case is whether to increase #rows or #columns. An option could be:
def place_ship(ship, start_position, orientation)
row = start_position[:row]
column = start_position[:column]
ship.length.times do
self.grid[row][column].ship = ship
self.grid[row][column].status = :occupied
orientation == :vertical ? row += 1 : column += 1
end
end
I removed the two (identical) methods, and just used the ternary operator ('?') to increase the correct variable after placing each ship part.
I usually use loop as below to request data form an external API or DB (redis pop):
records = []
loop do
record = MyHandler.new(token).fetch
break unless record
records.push(record)
end
It works, but to make it look better, I wonder whether there is any way to use an Enumerator. Does anyone know one?
Wrapping your code in an Enumerator is quite easy:
record_enumerator = Enumerator.new do |y|
loop do
record = MyHandler.new(token).fetch
break unless record
y << record
end
end
You can now iterate over the records using a block:
record_enumerator.each { |record|
# do something with record
}
Or fetch all records with:
records = record_enumerator.to_a
If MyHandler is your class, you could implement MyHandler#each instead and include Enumerable.
How about this?
while(record = MyHandler.new(token).fetch)
records.push(record)
end
That gets rid of the ugly loop/break logic.
Alternatively, you could create an ennumerable object instead of using the records array:
class RecordList
include Enumerable
attr :token
def initialize(token)
#token = token
end
def each
MyHandler.new(token).fetch
end
end
records = RecordList.new token
You can use while loops in ruby like so:
records = []
record = MyHandler.new(token).fetch
while record do
records << record
record = MyHandler.new(token).fetch
end
There might be an even more elegent way, but from the information provided, that's the best I can come up with.
If you are looking for the really short syntax, here you go:
records << record while record = MyHandler.new(token).fetch
It will work like a charm, the condition check is done before executing the loop body, hence record is always initialized.
So I am trying to create a Tree using Python to be able to try and read a text file, which has repeating quantities within the file, and try to create a tree out of these values and return the sentences with the Top 3 values (Explained in more detail below).
First of all I searched on wikipedia on how a tree is created and have also seen previous examples on stackoverflow like: This one. and This one. However I have only been able to do this so far as code goes:
import fileinput
setPhrasesTree = 0
class Branch():
def __init__(self, value):
self.left = None
self.right = None
self.value = value
class Tree():
def __init__(self):
self.root = None
self.found = False
#lessThan function needed to compare strings
def lessThan(self, a, b):
if len(a) < len(b):
loopCount = len(a)
else:
loopCount = len(b)
for pos in range(0, loopCount):
if a[pos] > b[pos]:
return False
return True
def insert(self, value):
self.root = self.insertAtBranch(self.root, value)
def exists(self, value):
#set the class variable found to False to assume it is not there
self.found = False
self.findAtBranch(self.root, value)
return self.found
#Used to fine a value in a tree
def findAtBranch(self, branch, value):
if branch == None:
pass
else:
if branch.value == value:
self.found = True
else:
self.findAtBranch(branch.left, value)
self.findAtBranch(branch.right, value)
def insertAtBranch(self, branch, value):
if branch == None:
return Branch(value)
else:
if self.lessThan(branch.value, value):
branch.right = self.insertAtBranch(branch.right, value)
else:
branch.left = self.insertAtBranch(branch.left, value)
return branch
def loadTree(filename, treeType):
if treeType == setPhrasesTree:
for sentence in fileinput.input("setPhrases.txt"):
print(sentence)
setPhrases.insert(sentence[:-1])
def findSentenceType(sentence):
if sentence.exists(sentence):
return setPhrasesTree
Here is what text file looks like. Bare in mind that it is purposefully laid out like this and not with a quantity value next to it (file name = setPhrases.txt):
Hi my name is Dave.
Thank-You.
What is your name?
I have done all my homework.
What time is dinner?
What is your name?
Thank-You.
Hi my name is Dave.
What is your name?
I have done all my homework.
What is your name?
Can you bring me a drink Please?
Can you bring me a drink Please?
What is your name?
Hi my name is Dave.
What is your name?
Can you bring me a drink Please?
Here is what I am trying to get my code to do. I need it to recognize that the first sentence, in the file, is the starting node. And then it needs to tally up all the other sentences that are the same and add a value to that sentence and just use the tree to be able to do this. (I have originally done this in another way, however I need to use a tree to be able to tally up and do all the other stuff) Here is what I mean:
I then want to be able to return the top 3 Phrases with the highest frequencies. So in this case the system would return the sentences (in this order):
What is your name?
Hi my name is Dave.
Can you bring me a drink please?
Any help is much appreciated. Also thank-you for your time.
Here you go, an implementation using a dictionary. Is this what you want?
import collections
def count_lines():
d = collections.defaultdict(int)
for line in open( "phrases.txt" ):
d[ line.strip() ] += 1
# we use the negative count as sort key, so the biggest ends up first
a = sorted( d.items(), key=lambda x : -x[1] )
for n, u in enumerate( a[:3] ):
print( u[0], "# count=", u[1] )
count_lines()
I have lots of math to do on lots of data but it's all based on a few base templates. So instead of say, when doing math between 2 arrays I do this:
results = [a[0]-b[1],a[1]-b[2],a[2]-b[3]]
I want to instead just put the base template: a[0]-b[1] and make it automatically fill say 50 places in the results array. So I don't always have to manually type it.
What would be the ways to do that? And would a good way be to create 1 method that does this automatically. And I just tell it the math and it fills out an array?
I have no clue, I'm really new to programming.
a = [2,3,4]
b = [1,2,3,4]
results = a.zip(b.drop(1)).take(50).map { |v,w| v - w }
Custom
a = [2,3,4..............,1000]
b = [1,2,3,4,.............900]
class Array
def self.calculate_difference(arr1,arr2,limit)
begin
result ||= Array.new
limit.send(:times) {|index| result << arr1[index]-arr2[index+=1]}
result
rescue
raise "Index/Limit Error"
end
end
end
Call by:
Array.calculate_difference(a,b,50)
Given I have code like the following, what do I need to do to make it work?
config = {} #options for faster csv
input_file = "foo.csv"
# can be in any class or module
def count_item_groups(items)
results = Hash.new(0)
(items || []).each do |current|
results[current.to_s] += 1
end
results
end
row_value_iterator = FasterCSV.foreach(input_file, config) do |row|
yield return row[1]
end
result = count_item_groups(row_value_iterator)
Versus code like this
def do_it_all
results = Hash.new(0)
FasterCSV.foreach(input_file, config) do |row|
results[row[1].to_s] += 1
end
results
end
Result should be a hash with keys of the row[1] values. yield return doesn't exist in Ruby, but I'm sure that Ruby can handle this type of code.
That's what I understand you are asking: "How can I transform a method like FasterCSV.foreach that works imperatively (by doing side-effects) to something functional (that yields values) so I can modularize my code".
Answer: In Ruby you can transform a each method to an Enumerator object with Object#enum_for. Now you could use your count_item_groups with the output of the map, but I'd suggest to use Facets' Enumerable#frequency:
results = FasterCSV.enum_for(:foreach, "file.csv", {}).map do |row|
row[1].to_s
end.frequency
#=> {"val1"=>3, "val2"=>1}
I'm not sure what you're asking, I assumed that is related to chainable feature.
Instead of passing the object iterator to another iterator as parameter, in ruby you can chain these iterators. It mignt look like this.
row_value_iterator = FasterCSV.foreach(input_file, config).map do |row|
row[1]
end
result = row_value_iterator.each_with_object(Hash.new(0)) do |current,results|
results[current.to_s] += 1
end
Or do it in truly chain style:
result = FasterCSV.foreach(input_file,config).each_with_object(Hash.new(0)) do |row,results|
results[row[1].to_s] += 1
end