Python use of class to create and manipulate a grid - class

Still trying to understand how to use class. I have now written the following:
`import random
class Grid():
def __init__(self, grid_row, grid_column):
self.__row = grid_row
self.__col = grid_column
self.__board=[]
def make_board(self):
for row in range(self.__row):
self.__board.append([])
for col in range(self.__col):
self.__board[row].append('0')
return self.__board
def change_tile(self):
choices = (0,1,2)
x = random.choice(choices)
y= random.choice(choices)
self.__board[x][y] = str(2)
def __repr__(self):
for row in self.__board:
print( " ".join(row))
g = Grid(3,3)
g.make_board()
g.change_tile()
print(g)
Firstly when I run this I get a grid printed followed by:
TypeError: __str__ returned non-string (type NoneType)
I don't understand why this happens. Second question. If I want to return the self.board, __str only returns the last row (0,0,0).With 'print' all three rows and columns are printed. Is there a way around the issue with 'return'?Is it an issue ( apart from the fact that I want to 'see' what I am doing)?
How would one call Grid(3,3) and get a grid with a randomly placed 2 without having to call each function separately as I have done in my example? Lastly why can I not use the integers 0 or 2, but have to convert everything to a string?. I hope that I have not exceeded the goodwill that exists on this forum by asking so many dumb questions!

The special methods __repr__ and __str__ are required to return a string. If there is no __str__ implementation given, the __repr__ will be used for the string conversion too.
Now in your case, __repr__ prints something instead of returning a string. It actually returns nothing, so None is implicitely returned. You have to change it to return a string. For example like this:
def __repr__(self):
return '\n'.join([' '.join(row) for row in self.__board])

Related

How to translate this code into python 3?

This code is originally written in Python 2 and I need to translate it in python 3!
I'm sorry for not sharing enough information:
Also, here's the part where self.D was first assigned:
def __init__(self,instance,transformed,describe1,describe2):
self.D=[]
self.instance=instance
self.transformed=transformed
self.describe1,self.describe2=describe1,describe2
self.describe=self.describe1+', '+self.describe2 if self.describe2 else self.describe1
self.column_num=self.tuple_num=self.view_num=0
self.names=[]
self.types=[]
self.origins=[]
self.features=[]
self.views=[]
self.classify_id=-1
self.classify_num = 1
self.classes=[]
def generateViews(self):
T=map(list,zip(*self.D))
if self.transformed==0:
s= int( self.column_num)
for column_id in range(s):
f = Features(self.names[column_id],self.types[column_id],self.origins[column_id])
#calculate min,max for numerical,temporal
if f.type==Type.numerical or f.type==Type.temporal:
f.min,f.max=min(T[column_id]),max(T[column_id])
if f.min==f.max:
self.types[column_id]=f.type=Type.none
self.features.append(f)
continue
d={}
#calculate distinct,ratio for categorical,temporal
if f.type == Type.categorical or f.type == Type.temporal:
for i in range(self.tuple_num):
print([type(self.D[i]) for i in range(self.tuple_num)])
if self.D[i][column_id] in d:
d[self.D[i][column_id]]+=1
else:
d[self.D[i][column_id]]=1
f.distinct = len(d)
f.ratio = 1.0 * f.distinct / self.tuple_num
f.distinct_values=[(k,d[k]) for k in sorted(d)]
if f.type==Type.temporal:
self.getIntervalBins(f)
self.features.append(f)
TypeError: 'map' object is not subscriptable
The snippet you have given is not enough to solve the problem. The problem lies in self.D which you are trying to subscript using self.D[i]. Please look into your code where self.D is instantiated and make sure that its an array-like variable so that you can subscript it.
Edit
based on your edit, please confirm that whether self.D[i] is also array-like for all i in the range mentioned in the code. you can do that by simply
print([type(self.D[i]) for i in range(self.tuple_num))
share the response of this code, so that I may help further.
Edit-2
As per your comments and the edited code snippet, it seems that self.D is the output of some map function. In python 2, map is a function that returns a list. However, in python3 map is a class that when invoked, creates a map object.
The simplest way to resolve this is the find out the line where self.D was first assigned, and whatever code is in the RHS, wrap it with a list(...) function.
Alternately, just after this line
T=map(list,zip(*self.D))
add the following
self.D = list(self.D)
Hope this will resolve the issue
We don't have quite enough information to answer the question, but in Python 3, generator and map objects are not subscriptable. I think it may be in your
self.D[i]
variable, because you claim that self.D is a list, but it is possible that self.D[i] is a map object.
In your case, to access the indexes, you can convert it to a list:
list(self.D)[i]
Or use unpacking to implicitly convert to a list (this may be more condensed, but remember that explicit is better than implicit):
[*self.D[i]]

Can operations on a numpy.memmap be deferred?

Consider this example:
import numpy as np
a = np.array(1)
np.save("a.npy", a)
a = np.load("a.npy", mmap_mode='r')
print(type(a))
b = a + 2
print(type(b))
which outputs
<class 'numpy.core.memmap.memmap'>
<class 'numpy.int32'>
So it seems that b is not a memmap any more, and I assume that this forces numpy to read the whole a.npy, defeating the purpose of the memmap. Hence my question, can operations on memmaps be deferred until access time?
I believe subclassing ndarray or memmap could work, but don't feel confident enough about my Python skills to try it.
Here is an extended example showing my problem:
import numpy as np
# create 8 GB file
# np.save("memmap.npy", np.empty([1000000000]))
# I want to print the first value using f and memmaps
def f(value):
print(value[1])
# this is fast: f receives a memmap
a = np.load("memmap.npy", mmap_mode='r')
print("a = ")
f(a)
# this is slow: b has to be read completely; converted into an array
b = np.load("memmap.npy", mmap_mode='r')
print("b + 1 = ")
f(b + 1)
Here's a simple example of an ndarray subclass that defers operations on it until a specific element is requested by indexing.
I'm including this to show that it can be done, but it almost certainly will fail in novel and unexpected ways, and require substantial work to make it usable.
For a very specific case it may be easier than redesigning your code to solve the problem in a better way.
I'd recommend reading over these examples from the docs to help understand how it works.
import numpy as np
class Defered(np.ndarray):
"""
An array class that deferrs calculations applied to it, only
calculating them when an index is requested
"""
def __new__(cls, arr):
arr = np.asanyarray(arr).view(cls)
arr.toApply = []
return arr
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
## Convert all arguments to ndarray, otherwise arguments
# of type Defered will cause infinite recursion
# also store self as None, to be replaced later on
newinputs = []
for i in inputs:
if i is self:
newinputs.append(None)
elif isinstance(i, np.ndarray):
newinputs.append(i.view(np.ndarray))
else:
newinputs.append(i)
## Store function to apply and necessary arguments
self.toApply.append((ufunc, method, newinputs, kwargs))
return self
def __getitem__(self, idx):
## Get index and convert to regular array
sub = self.view(np.ndarray).__getitem__(idx)
## Apply stored actions
for ufunc, method, inputs, kwargs in self.toApply:
inputs = [i if i is not None else sub for i in inputs]
sub = super().__array_ufunc__(ufunc, method, *inputs, **kwargs)
return sub
This will fail if modifications are made to it that don't use numpy's universal functions. For instance percentile and median aren't based on ufuncs, and would end up loading the entire array. Likewise, if you pass it to a function that iterates over the array, or applies an index to substantial amounts the entire array will be loaded.
This is just how python works. By default numpy operations return a new array, so b never exists as a memmap - it is created when + is called on a.
There's a couple of ways to work around this. The simplest is to do all operations in place,
a += 1
This requires loading the memory mapped array for reading and writing,
a = np.load("a.npy", mmap_mode='r+')
Of course this isn't any good if you don't want to overwrite your original array.
In this case you need to specify that b should be memmapped.
b = np.memmap("b.npy", mmap+mode='w+', dtype=a.dtype, shape=a.shape)
Assigning can be done by using the out keyword provided by numpy ufuncs.
np.add(a, 2, out=b)

Ruby Optional Parameters method calling with one or two

The method should return words multiple times. The method should take 2 paramters word and n = number times word should be printed. But I want the second parameter to be optional. I can call the method with single parameter and it should return the same word. If second parameter used then it should return the same word that many times.
def repeat(word,n)
n.times {word}
end
p repeat("abc", 2) <- this works
but what if I only want
p repeat("abc")
Old question, but I had a similar problem today and solved it like this:
def repeat(word, n=1)
n.times {word}
end
If you call it like this:
p repeat("abc") it will only repeat it once, but you can pass in a value for n it will repeat however many times you want. If you want it to print out the actual word, this slight modification to the OP's method will do that.
def repeat(word, n=1)
n.times {puts word}
end
and call it with repeat("abc") or repeat("abc", 2)

Scala String and Char Types

val args = "To now was far back saw the *$# giant planet itself, het a won"
Find and sort distinct anagram pairs from "args":
now won
was saw
the het
First I clean up the args and put them in an array.
val argsArray = args.replaceAll("[^a-zA-Z0-9\\s]", "").toLowerCase.split(" ").distinct.sorted
argsArray: Array[String] = Array("", a, back, far, giant, het, itself, now, planet, saw, the, to, was, won)
My idea is to reduce each word to an array of char, then sort, then compare. But I get stuck because the following returns the wrong data type ---- String = [C#2736f24a
for (i <- 0 until argsArray.length - 1){
val j = i + 1
if(argsArray(i).toCharArray.sorted == argsArray(j).toCharArray.sorted) {
println(argsArray(i).toCharArray + " " + argsArray(j).toCharArray)
}
}
I assume there are better ways to solve this, but what I really want to learn is how to deal with this data type problem, so please help me solve that and then I will refactor later. Thank you.
[C#<whatever> is just how Array[Char] is converted to String on JVM. Remove calls to toCharArray from println and it'll print the strings you want. The second error, with the current code in the question, is the equality check: == on arrays checks that they are the same object, and since sorted will always create a new array, the left and right sides are always different objects even if they have the same elements.

Looping through documents in matlab

I am attempting to loop through the variable 'docs' which is a cell array that holds strings, i need to make a for loop that colllects the terms in a cell array and then uses command 'lower' and unique to create a dictionary.
Here is the code i've tried sp far and i just get errors
docsLength = length(docs);
for C = 1:docsLength
list = tokenize(docs, ' .,-');
Mylist = [list;C];
end
I get these errors
Error using textscan
First input must be of type double or string.
Error in tokenize (line 3)
C = textscan(str,'%s','MultipleDelimsAsOne',1,'delimiter',delimiters);
Error in tk (line 4)
list = tokenize(docs, ' .,-');
Generically, if you get an "must be of type" error, that means you are passing the wrong sort of input to a function. In this case you should look at the point in your code where this is taking place (here, in tokenize when textscan is called), and doublecheck that the input going in is what you expect it to be.
As tokenize is not a MATLAB builtin function, unless you show us that code we can't say what those inputs should be. However, as akfaz mentioned in comments, it is likely that you want to pass docs{C} (a string) to tokenize instead of docs (a cell array). Otherwise, there's no point in having a loop as it just repeatedly passes the same input, docs, into the function.
There are additional problems with the loop:
Mylist = [list; C]; will be overwritten each loop to consist of the latest version of list plus C, which is just a number (the index of the loop). Depending on what the output of tokenize looks like, Mylist = [Mylist; list] may work but you should initialise Mylist first.
Mylist = [];
for C = 1:length(docs)
list = tokenize(docs{C}, ' .,-');
Mylist = [Mylist; list];
end