John Joseph said unto the world upon 08/01/06 06:36 AM:
> --- Guillermo Fernandez Castellanos
> <[EMAIL PROTECTED]> wrote:
> 
> 
>>Hi,
>>
>>Look at this:
>> >>> i=[1,2,3]
>> >>> i[len(i)]
>>Traceback (most recent call last):
>>   File "<stdin>", line 1, in ?
>>IndexError: list index out of range
>>
>>
>>This means that I have tried to access an element
>>that is out of the 
>>list, in this case i[3], that is, the 4th element of
>>the list.
>>
>>You are doing the same. You do a
>>j in range(len(seats))
>>and then you are accessing your list with seats[j]
>>and seats[j+1]. What 
>>happens when j = len(seats)-1 and you call
>>seats[j+1]? :-)
>>
>>It happens indeed the same that in the example I
>>gave you first.
>>
>>Hope it helps. Good luck,
>>
> 
> 
> Thanks for the advice  
>  But I need to display the results 
>   What should I do in the for loop  for this message
> to go 
>   my for loop is as 
> 
> for   j in range(length)  :
>         if seats[j] <> seats[j+1]:
>                 print " The Seat", j , "And the seat",
> j+1 , "value, which are", seats[j]," and", seats[j+1],
> "are not same" 
>         else:
>                 print "The Seats ",j ,"And the seats",
> j+1, "Values,", seats[j], "and", seats[j+1], "are
> same"
>       Thanks 
>          Joseph John 


Joseph,

I think Guillermo has already given you the answer :-).  But, I'll 
make it more explicit.

I'll also do a rather more. My intent is to give you some idea of how 
you can go about incrementally improving your code.

The code you posted is doing something like:

 >>> a_list = [7,8,7]
 >>> for index in range(len(a_list)):
        print index, a_list[index]
        print index + 1, len(a_list), a_list[index + 1]

        
0 7
1 3 8
1 8
2 3 7
2 7
3 3

Traceback (most recent call last):
   File "<pyshell#97>", line 3, in -toplevel-
     print index + 1, len(a_list), a_list[index + 1]
IndexError: list index out of range

Examine the output. When the iteration hits the last member of the 
list (when it gets to the final element of range(len(a_list)), there 
is no next element of the list, so the request to print the next 
element doesn't work. The list length is 3, so I get the same 
exception as if I'd done:

 >>> a_list[3]

Traceback (most recent call last):
   File "<pyshell#16>", line 1, in -toplevel-
     a_list[3]
IndexError: list index out of range

directly. That suggests *not* asking for an iteration which uses up 
the list -- leave a next element and the code will work:

 >>> for index in range(len(a_list) - 1):  # Note the difference
        print index, a_list[index]
        print index + 1, len(a_list), a_list[index + 1]

        
0 7
1 3 8
1 8
2 3 7
 >>>


Of course, as you pointed out in your OP, right now, even with this 
fix, you will only be testing for sequential duplicates. My test list

a_list = [7,8,7]

has dupes, but your approach won't find them.

Warning: I'm going to go into a number of issues that you might not 
yet entirely understand. If I lose you, don't worry; just ask about it.


Let's both fix the requirement that the duplicates be sequential and 
start putting the code into functions.

Consider this:

 >>> def dupe_detector_1(sequence):
        for item in sequence:
                if sequence.count(item) > 1:
                        print "%s is duplicated!" %item

                        
 >>> dupe_detector_1(a_list)
7 is duplicated!
7 is duplicated!
 >>>

OK, that might be better, as we can find non-sequential duplicates. 
But, there are two problems. 1) The duplication warning is duplicated 
:-) and 2)

 >>> a_tuple = (4,3,4)
 >>> dupe_detector_1(a_tuple)

Traceback (most recent call last):
   File "<pyshell#47>", line 1, in -toplevel-
     dupe_detector_1(a_tuple)
   File "<pyshell#28>", line 3, in dupe_detector_1
     if sequence.count(item) > 1:
AttributeError: 'tuple' object has no attribute 'count'
 >>>

The function signature seems to indicate it will work for all 
sequences, but it chokes on tuples.

The second problem is easy to fix:

 >>> def dupe_detector_2(sequence):
        # coerce to a list as lists have count methods.
        sequence = list(sequence)
        for item in sequence:
                if sequence.count(item) > 1:
                        print "%s is duplicated!" %item

                        
 >>> dupe_detector_2((1,1,2))
1 is duplicated!
1 is duplicated!
 >>>

1 down, 1 to go.

 >>> def dupe_detector_3(sequence):
        sequence = list(sequence)
        seen_dupes = []
        for item in sequence:
                if item in seen_dupes:
                        # if it is there, we already know it is duplicated
                        continue
                elif sequence.count(item) > 1:
                        print "%s is duplicated!" %item
                        seen_dupes.append(item)

                        
 >>> dupe_detector_3(a_list)
7 is duplicated!
 >>>

That's much better :-)


There remain 2 things I'd want to do differently.

First, I'd separate the print logic from the detection logic:

 >>> def dupe_detector_4(sequence):
        '''returns a list of items in sequence that are duplicated'''
        sequence = list(sequence)
        seen_dupes = []
        for item in sequence:
                if item in seen_dupes:
                        # if it is there, we already know it is duplicated
                        continue
                elif sequence.count(item) > 1:
                        seen_dupes.append(item)
        return seen_dupes

 >>> big_list = [1,42,3,4,2,3,54,6,7,3,45,6,4,32,43,5,32,4,4,42,3,42,3]
 >>> dupes_in_big_list = dupe_detector_4(big_list)
 >>> dupes_in_big_list
[42, 3, 4, 6, 32]

OK, you might say "fine, but I *wanted* an on-screen report". Let's do 
that this way:

 >>> def print_dupe_report(sequence):
        '''prints a report of items in sequence that are duplicated'''
        dupes = dupe_detector_4(sequence)
        dupes.sort()
        for d in dupes:
                print "%s was duplicated" %d

                
 >>> print_dupe_report(big_list)
3 was duplicated
4 was duplicated
6 was duplicated
32 was duplicated
42 was duplicated
 >>>

The advantage of this is you might well want to do what 
dupe_detector_4 does without the screen output. Making the function 
have a smaller job makes it easier to reuse in other contexts.

The last thing is a bit subtle. Say I had a sequence of length 10**6 
where most items were duplicated. dupe_detector_4 has to iterate over 
the entire long sequence, and continually hit the continue clause as 
it will have seen the item already.

This last version will fix that, too:

 >>> def dupe_detector_5(sequence):
        '''returns a list of items in sequence that are duplicated'''
        sequence = list(sequence)
        seen_dupes = []
        for item in set(sequence):   # Note the difference
                if sequence.count(item) > 1:
                        seen_dupes.append(item)
        return seen_dupes

 >>> dupes_in_big_list = dupe_detector_5(big_list)
 >>> dupes_in_big_list
[32, 3, 4, 6, 42]
 >>>

We no longer need the continue clause, as converting to set ensures we 
won't ever deal with the same item twice:

 >>> set((1,1,1,2,2,2,2,2,3,4,4,5))
set([1, 2, 3, 4, 5])


And, preventing us from dealing with the same item twice is what makes 
this better. To see that, consider:

 >>> def iteration_comparison(sequence):
        list_count = 0
        set_count = 0
        for i in list(sequence):
                list_count += 1
        for i in set(sequence):
                set_count += 1
        print list_count, set_count

        
 >>> iteration_comparison((1,2,3,4))
4 4
 >>> iteration_comparison((1,2,3,4,1,2,3,4,1,2,3,4,5,1,2,3,4,1,2,3,4))
21 5
 >>>

For sequences with a lot of duplication, the set version (as in 
dupe_detector_5) has to iterate over far fewer items. That'll be quicker.

OK, I hope most of that made sense.

Best,

Brian vdB


_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to