469,610 Members | 2,357 Online

# Searching and manipulating lists of tuples

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:
def algorith(list,str): .... flag = True
.... for l in list:
.... if l == str:
.... l += 1
.... flag = False
.... if flag:
.... list.append((str,1))
....
But:
algorith(L,"X")

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?

Jun 12 '06 #1
7 5672 MTD wrote:
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
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.

Jun 12 '06 #2

MTD wrote:
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:
def algorith(list,str): ... flag = True
... for l in list:
... if l == str:
... l += 1
... flag = False
... if flag:
... list.append((str,1))
...
But:
algorith(L,"X")

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. 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()

Jun 12 '06 #3
> Yes, use the proper tool for the job. Tuples are immutable (they are
your string, the value would be the count.

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

Jun 12 '06 #4
MTD wrote:
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:
def algorith(list,str):
... flag = True
... for l in list:
... if l == str:
... l += 1
... flag = False
... if flag:
... list.append((str,1))
...
But:

algorith(L,"X")

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[s] += 1
else:
d[s] = 1

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Love me, love my blog http://holdenweb.blogspot.com
Recent Ramblings http://del.icio.us/steve.holden

Jun 12 '06 #5

MTD wrote:
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[i] += 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

-----------------------------------

Gerard

Jun 12 '06 #6
Steve Holden <st***@holdenweb.com> wrote:
def algorith(d, s):
if s in d:
d[s] += 1
else:
d[s] = 1

def algorith(d, s):
d[s] = 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).

--
\S -- si***@chiark.greenend.org.uk -- http://www.chaos.org.uk/~sion/
___ | "Frankly I have no feelings towards penguins one way or the other"
\X/ | -- Arthur C. Clarke
her nu becomeþ se bera eadward ofdun hlæddre heafdes bæce bump bump bump
Jun 12 '06 #7
MTD wrote:
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:
def algorith(list,str):

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 == str:
... l += 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[i] = (name, count+1)
break
else:
alist.append( (astring, 1) )
(snip)
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Jun 12 '06 #8

### This discussion thread is closed

Replies have been disabled for this discussion.

### Similar topics

 10 posts views Thread by Ivan Voras | last post: by 3 posts views Thread by Thorsten Kampe | last post: by 18 posts views Thread by Elbert Lev | last post: by 3 posts views Thread by Nickolay Kolev | last post: by 24 posts views Thread by Lasse Vågsæther Karlsen | last post: by 4 posts views Thread by Peter Notebaert | last post: by 122 posts views Thread by C.L. | last post: by 27 posts views Thread by seberino | last post: by 25 posts views Thread by beginner | last post: by reply views Thread by devgraph | last post: by 1 post views Thread by strativab | last post: by reply views Thread by billypeterson | last post: by reply views Thread by Drake Tucker | last post: by reply views Thread by strativab | last post: by reply views Thread by eddparker01 | last post: by reply views Thread by devrayhaan | last post: by reply views Thread by neerajsundriyal | last post: by reply views Thread by aprens | last post: by