What's more elegant way to check for anagram? - anagram

I can't imagine better way to check for anagram than my solution:
def anagram(self,s,t):
if len(s) != len(t):
return False
else:
for elem1 in s:
current_looking = elem1
if current_looking in t:
current_index = t.index(current_looking)
t = t[:current_index] + t[current_index+1:]
else:
return False
return True
Or this:
def anagram(s1,s2):
return sorted(s1) == sorted(s2)
Or maybe there is another one?

collections.Counter is as succinct and faster than the sorting approach (O(n) < O(n log(n))):
from collections import Counter
def anagram(a, b):
return Counter(a) == Counter(b)
You can boost performance at the expense of terseness:
def anagram(a, b):
return len(a) == len(b) and Counter(a) == Counter(b)

Related

Error while validating User Input in Python

I am having problem validating the user input (I am asking user if they wish to continue with the program of calculating factorial). The code is as follows: (User input validation is towards the end of the main function and I have not included the factorial function)
def main():
valid_inp = False
usr_continue = True
while usr_continue:
while valid_inp == False:
usr_inp = int(input('Please ENTER a number: '))
if usr_inp < 0:
print('ERROR, INVALID INPUT')
else:
valid_inp = True
continue
result = factorial(usr_inp)
print(str(result) + '\n')
con_inp = str(input('Would you like to continue ? '))
if con_inp == 'Y' or con_inp == 'y':
usr_continue
elif con_inp == 'N' or con_inp == 'n':
print('Goodbye...')
break
main()
Make a function that only returns on valid input. Use an exception handler to deal with bad integer input, then validate the integer is the range you want:
from math import factorial
def get_nonnegative_integer(prompt):
while True:
try:
val = int(input(prompt)) # bad input for int such as "abc" will raise ValueError
if val >= 0: # good input will be range-checked
return val
else:
print('enter a number >= 0')
except ValueError:
print('invalid input for integer')
def main():
while True:
usr_inp = get_nonnegative_integer('Please enter a number: ')
result = factorial(usr_inp)
print(result)
con_inp = input('Would you like to continue(Y/n)? ').upper() # default Yes
if con_inp.startswith('N'):
print('Goodbye...')
break
main()

Binary-search without an explicit array

I want to perform a binary-search using e.g. np.searchsorted, however, I do not want to create an explicit array containing values. Instead, I want to define a function giving the value to be expected at the desired position of the array, e.g. p(i) = i, where i denotes the position within the array.
Generating an array of values regarding the function would, in my case, be neither efficient nor elegant. Is there any way to achieve this?
What about something like:
import collections
class GeneratorSequence(collections.Sequence):
def __init__(self, func, size):
self._func = func
self._len = size
def __len__(self):
return self._len
def __getitem__(self, i):
if 0 <= i < self._len:
return self._func(i)
else:
raise IndexError
def __iter__(self):
for i in range(self._len):
yield self[i]
This would work with np.searchsorted(), e.g.:
import numpy as np
gen_seq = GeneratorSequence(lambda x: x ** 2, 100)
np.searchsorted(gen_seq, 9)
# 3
You could also write your own binary search function, you do not really need NumPy in this case, and it can actually be beneficial:
def bin_search(seq, item):
first = 0
last = len(seq) - 1
found = False
while first <= last and not found:
midpoint = (first + last) // 2
if seq[midpoint] == item:
first = midpoint
found = True
else:
if item < seq[midpoint]:
last = midpoint - 1
else:
first = midpoint + 1
return first
Which gives identical results:
all(bin_search(gen_seq, i) == np.searchsorted(gen_seq, i) for i in range(100))
# True
Incidentally, this is also WAY faster:
gen_seq = GeneratorSequence(lambda x: x ** 2, 1000000)
%timeit np.searchsorted(gen_seq, 10000)
# 1 loop, best of 3: 1.23 s per loop
%timeit bin_search(gen_seq, 10000)
# 100000 loops, best of 3: 16.1 µs per loop
Inspired by #norok2 comment, I think you can use something like this:
def f(i):
return i*2 # Just an example
class MySeq(Sequence):
def __init__(self, f, maxi):
self.maxi = maxi
self.f = f
def __getitem__(self, x):
if x < 0 or x > self.maxi:
raise IndexError()
return self.f(x)
def __len__(self):
return self.maxi + 1
In this case f is your function while maxi is the maximum index. This of course only works if the function f return values in sorted order.
At this point you can use an object of type MySeq inside np.searchsorted.

More efficient fillna(numpy)

I need an array version of a function similar to Pandas.fillna, in the forum I collected a lot of answers to create the following function, but it is still 3 times times slower than Pandas.fillna, I want to know if there is a better way to optimize, thank you.
def fillna(self,axis=None,mask=None,value=None,method='pad'):
""" array fillna
Parameters
----------
self : 1d/2d
axis : axis(0 or 1)
mask : Custom mask, or Built np.isfinite(x)
value : int
method : 'back', 'pad', 'mean'
--------
"""
x = np.asarray(self)
if mask is None: mask = np.isfinite(x)
if (not value is None)|(method=='mean'):
out = x.copy()
if x.ndim == 1:
if method=='mean':
out[~mask] = np.nanmean(x)
else: out[~mask] = value
else:
vask = ~mask * (np.nanmean(x,1)[:,None] if axis==1 else np.nanmean(x,0))
out[~mask] = vask[~mask]
else:
if axis is None: axis = 0
if x.ndim==1:
if method=='pad':
idx = np.where(mask,np.arange(mask.shape[0]),0)
np.maximum.accumulate(idx,axis=0,out=idx)
return x[idx]
elif method=='back':
idx = np.where(mask[::-1],np.arange(mask.shape[0]),0)
np.maximum.accumulate(idx,axis=0,out=idx)
return x[mask.shape[0]-idx[::-1]-1]
else: return x
if axis==1:
if method=='back': mask = mask[:, ::-1]
idx = np.where(mask,np.arange(mask.shape[1]),0)
else:
if method=='back': mask = mask[::-1,:]
idx = np.where(mask,np.arange(mask.shape[0])[:,None],0)
np.maximum.accumulate(idx,axis=axis,out=idx)
if axis==1:
if method=='back': idx = idx.shape[1]-idx[:, ::-1] - 1
out = x[np.arange(idx.shape[0])[:,None], idx]
else:
if method=='back': idx = idx.shape[0]-idx[::-1, :] - 1
out = x[idx,np.arange(idx.shape[1])]
return out

How to resize rows in a QTreeView and a QStandardItemModel?

I'd like to set my rows to a fixed height. I've found an example using QAbstractItemModel, but I'm using QStandardItemModel. When I run the app, the QTreeView is blank. Any thoughts on how I could get this working for a QStandardItemModel?
import sys
from PySide import QtCore, QtGui
class TreeItem(object):
def __init__(self, data, parent=None):
self.parentItem = parent
self.data = data
self.childItems = []
def appendChild(self, item):
self.childItems.append(item)
def row(self):
if self.parentItem:
return self.parentItem.childItems.index(self)
return 0
class TreeModel(QtCore.QAbstractItemModel):
def __init__(self, parent=None):
super(TreeModel, self).__init__(parent)
self.rootItem = TreeItem(None)
for i, c in enumerate("abcdefg"):
child = TreeItem([i, c], self.rootItem)
self.rootItem.appendChild(child)
parent = self.rootItem.childItems[1]
child = TreeItem(["down", "down"], parent)
parent.appendChild(child)
def columnCount(self, parent):
return 2
def data(self, index, role):
if not index.isValid():
return None
if role == QtCore.Qt.DisplayRole:
item = index.internalPointer()
return item.data[index.column()]
elif role == QtCore.Qt.SizeHintRole:
print "giving size hint"
return QtCore.QSize(10, 10)
return None
def flags(self, index):
if not index.isValid():
return QtCore.Qt.NoItemFlags
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return ["A", "B"][section]
return None
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.childItems[row]
if childItem:
return self.createIndex(row, column, childItem)
else:
return QtCore.QModelIndex()
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
parentItem = index.internalPointer().parentItem
if parentItem == self.rootItem:
return QtCore.QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
return len(parentItem.childItems)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
model = TreeModel()
view = QtGui.QTreeView()
view.setModel(model)
view.setWindowTitle("Simple Tree Model")
view.show()
sys.exit(app.exec_())
Also, I've been looking around for the meaning of the term delegate in Qt, but the concept still isn't clicking in my head yet. Any insight into that would be appreciated as well!
You generally do this using QItemDelegates (or QStyledItemDelegate if you want stylesheet styling to work) by overriding the sizeHint method and always returning a size of a fixed height.
class MyDelegate(QtGui.QStyledItemDelegate):
def sizeHint(self, option, index):
my_fixed_height = 30
size = super(MyDelegate, self).sizeHint(option, index)
size.setHeight(my_fixed_height)
return size
view = QtGui.QTreeView()
delegate = MyDelegate()
view.setItemDelegate(delegate)

How to add custom statistics in Grinder

In Grinder we'd like to add customized statistics
grinder.statistics.registerSummaryExpression("connTimeout", "userLong0")
grinder.statistics.forCurrentTest.addLong("userLong0", 1)
And it seems to be successful as we can get the customized field in Grinder out file
The problem is that the value of that statistics is always 0
Here is the complete script implemented by Jython
# -*- coding: utf-8 -*-
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from com.netease.cloud.ndir.performance import Query
from com.netease.cloud.ndir.performance import QueryReturnCode
def writeToFile(text):
filename = "response.log"
file = open(filename, "a")
file.write(str(text) + "\n")
file.close()
ndir_client = grinder.getProperties().getProperty("ndirClient")
query_file = grinder.getProperties().getProperty("queryFile")
request = Query("grinder.properties", query_file)
grinder.statistics.registerSummaryExpression("connTimeout", "userLong0")
grinder.statistics.registerSummaryExpression("readTimeout", "userLong1")
grinder.statistics.registerSummaryExpression("code!=200", "userLong2")
grinder.statistics.registerSummaryExpression("docs=[]", "userLong3")
grinder.statistics.registerSummaryExpression("unknown", "userLong4")
class TestRunner:
def __init__(self):
grinder.statistics.delayReports=True
def initialSleep(self):
sleepTime = grinder.threadNumber * 20 # per thread
grinder.sleep(sleepTime, 0)
def query(self):
if ndir_client == "true":
query = request.randomQueryByNdirClient
else:
query = request.randomQueryByHttpGet
try:
result = query()
except:
writeToFile("exception")
grinder.statistics.forCurrentTest.addLong("userLong4", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
if result == 0:
grinder.getStatistics().getForCurrentTest().setSuccess(True)
return
elif result == 1:
grinder.statistics.forCurrentTest.addLong("userLong0", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
elif result == 2:
grinder.statistics.forCurrentTest.addLong("userLong1", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
elif result == 3:
grinder.statistics.forCurrentTest.addLong("userLong2", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
elif result == 4:
grinder.statistics.forCurrentTest.addLong("userLong3", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(True)
return
else:
grinder.statistics.forCurrentTest.addLong("userLong4", 1)
grinder.getStatistics().getForCurrentTest().setSuccess(False)
return
request = Test(120, 'query').wrap(query)
def __call__(self):
if grinder.runNumber == 0:
self.initialSleep()
self.request(self)
I suspect the problem is that you are marking tests as failed, but expecting the statistics to appear in the summary. Only successful tests are accumulated into the summary statistics.
Try registering data log expressions as well
grinder.statistics.registerDataLogExpression("connTimeout", "userLong0")
grinder.statistics.registerDataLogExpression("readTimeout", "userLong1")
grinder.statistics.registerDataLogExpression("code!=200", "userLong2")
grinder.statistics.registerDataLogExpression("docs=[]", "userLong3")
grinder.statistics.registerDataLogExpression("unknown", "userLong4")
Then you'll at least see the values in the data log file of the worker process.