Searching and manipulating lists of tuples

M

MTD

Hello,

I'm wondering if there's a quick way of resolving this problem.

In a program, I have a list of tuples of form (str,int), where int is a
count of how often str occurs

e.g. L = [ ("X",1),("Y",2)] would mean "X" occurs once and "Y" occurs
twice

If I am given a string, I want to search L to see if it occurs already.
If it does, I find the corresponding tuple and increment the integer
part. If not, I append the new element with int = 1.

e.g.

algorithm(L, "X") would produce output L = [("X",2),("Y",2)]
algorithm(L,"Z") would produce L = [("X",1),("Y",2),("Z",1)]

I tried to create an algorithm of the following form:.... flag = True
.... for l in list:
.... if l[0] == str:
.... l[1] += 1
.... flag = False
.... if flag:
.... list.append((str,1))
....


But:

gives:

Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 5, in algorith
TypeError: object does not support item assignment


So clearly that doesn't work... any ideas?
 
M

Mike Kent

MTD said:
Hello,

I'm wondering if there's a quick way of resolving this problem.

In a program, I have a list of tuples of form (str,int), where int is a
count of how often str occurs
....

So clearly that doesn't work... any ideas?

Yes, use the proper tool for the job. Tuples are immutable (they are
read-only once created). Instead use a dictionary. They key would be
your string, the value would be the count.

Also, don't use 'str' as the name for a string, as it shadows the
built-in 'str' function.
 
H

Harold Fellermann

MTD said:
Hello,

I'm wondering if there's a quick way of resolving this problem.

In a program, I have a list of tuples of form (str,int), where int is a
count of how often str occurs

e.g. L = [ ("X",1),("Y",2)] would mean "X" occurs once and "Y" occurs
twice

If I am given a string, I want to search L to see if it occurs already.
If it does, I find the corresponding tuple and increment the integer
part. If not, I append the new element with int = 1.

e.g.

algorithm(L, "X") would produce output L = [("X",2),("Y",2)]
algorithm(L,"Z") would produce L = [("X",1),("Y",2),("Z",1)]

I tried to create an algorithm of the following form:... flag = True
... for l in list:
... if l[0] == str:
... l[1] += 1
... flag = False
... if flag:
... list.append((str,1))
...


But:

gives:

Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 5, in algorith
TypeError: object does not support item assignment

Your approach does not work because the tuples in the list a imutable.
The problem occurs in the line l[1] += 1. You could solve the problem
by using lists of lists, rather than lists of tuples. However, if you
only
want to know the frequency of items in the list (i.e. want to build a
histogram)
and you are not interested in the original order of items in the list,
a
dictionary is suited better for this task, because you avoid the linear
time
behavior of:

def histogram(liste) :
result = {}
for item in liste :
result[item] = result.get(item,0) + 1
return result.items()
 
M

MTD

Yes, use the proper tool for the job. Tuples are immutable (they are
read-only once created). Instead use a dictionary. They key would be
your string, the value would be the count.

Wow, I really should have thought of that! Thanks.
 
S

Steve Holden

MTD said:
Hello,

I'm wondering if there's a quick way of resolving this problem.

In a program, I have a list of tuples of form (str,int), where int is a
count of how often str occurs

e.g. L = [ ("X",1),("Y",2)] would mean "X" occurs once and "Y" occurs
twice

If I am given a string, I want to search L to see if it occurs already.
If it does, I find the corresponding tuple and increment the integer
part. If not, I append the new element with int = 1.

e.g.

algorithm(L, "X") would produce output L = [("X",2),("Y",2)]
algorithm(L,"Z") would produce L = [("X",1),("Y",2),("Z",1)]

I tried to create an algorithm of the following form:

... flag = True
... for l in list:
... if l[0] == str:
... l[1] += 1
... flag = False
... if flag:
... list.append((str,1))
...


But:



gives:

Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 5, in algorith
TypeError: object does not support item assignment


So clearly that doesn't work... any ideas?
[Nit: try not to use built-in names like "list" and "str" for your own
purposes, as it stops you from using the bult-ins].

There are many ways you could do this more efficiently. The most
efficient solution doesn't use a list at all, but a dictionary (the
following code is untested):

def algorith(d, s):
if s in d:
d += 1
else:
d = 1

regards
Steve
 
G

Gerard Flanagan

MTD said:
Hello,

I'm wondering if there's a quick way of resolving this problem.

In a program, I have a list of tuples of form (str,int), where int is a
count of how often str occurs

e.g. L = [ ("X",1),("Y",2)] would mean "X" occurs once and "Y" occurs
twice

If I am given a string, I want to search L to see if it occurs already.
If it does, I find the corresponding tuple and increment the integer
part. If not, I append the new element with int = 1.

e.g.

algorithm(L, "X") would produce output L = [("X",2),("Y",2)]
algorithm(L,"Z") would produce L = [("X",1),("Y",2),("Z",1)]

just a thought:

class MyList(object):

def __init__(self):
self._items = []
self._counts = []

def append(self, value):
try:
i = self._items.index(value)
self._counts += 1
except ValueError:
self._items.append(value)
self._counts.append(1)

def __getitem__(self, index):
return self._items[index], self._counts[index]

def __repr__(self):
return str(zip(self._items, self._counts))

m = MyList()

print m
m.append('K')
print m
m.append('K')
print m
m.append('Z')
print m
 
S

Sion Arrowsmith

Steve Holden said:
def algorith(d, s):
if s in d:
d += 1
else:
d = 1


def algorith(d, s):
d = d.get(s, 0) + 1

And the OP should note that converting between dict d and list of
pairs L is simply a matter of L = d.items() and d = dict(L) (assuming
some other part of the program wants that list representation).
 
B

bruno at modulix

MTD said:
Hello,

I'm wondering if there's a quick way of resolving this problem.

In a program, I have a list of tuples of form (str,int), where int is a
count of how often str occurs

e.g. L = [ ("X",1),("Y",2)] would mean "X" occurs once and "Y" occurs
twice

If I am given a string, I want to search L to see if it occurs already.
If it does, I find the corresponding tuple and increment the integer
part. If not, I append the new element with int = 1.

e.g.

algorithm(L, "X") would produce output L = [("X",2),("Y",2)]
algorithm(L,"Z") would produce L = [("X",1),("Y",2),("Z",1)]

if you don't mind about ordering:

def algorithm(items, target):
d = dict(items)
try:
d[target] += 1
except KeyError:
d[target] = 1
items[:] = d.items()

Now it would probably be better to directly use a dict instead of a list
of tuples if possible...
I tried to create an algorithm of the following form:

Using 'list' and 'str' as identifiers will shadow the eponym builtin
types in this function. This may or may not be a problem here, but it's
usually better to avoid doing so.
... flag = True
... for l in list:
... if l[0] == str:
... l[1] += 1
tuples are immutable. Hence the exception.
... flag = False
'break'ing here would avoid useless iterations. And also allow the use
of the 'else' clause of the for loop, si you don't need a flag.
... if flag:
... list.append((str,1))

...

While there are pretty good reasons to favor the dict-based solution
(unless you really insist on having sub-optimal code of course !-), the
following is a somewhat more pythonic rewrite of your original code:

def algogo(alist, astring):
for i, (name, count) in enumerate(alist):
if name == astring:
alist = (name, count+1)
break
else:
alist.append( (astring, 1) )


(snip)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top