failbetter
failbetter

Reputation: 143

Why is this object regarded as integer when I think it's a list?

This is a practice problem, which reads:

Define a procedure that takes in a string of numbers from 1-9 and outputs a list with the following parameters:

  1. Every number in the string should be inserted into the list.

  2. If a number x in the string is less than or equal to the preceding number y, the number x should be inserted into a sublist. Continue adding the following numbers to the sublist until reaching a number z that is greater than the number y. Then add this number z to the normal list and continue.

Examples:

string = '543987'; result = [5,[4,3],9,[8,7]]

string= '987654321'; result = [9,[8,7,6,5,4,3,2,1]]

string = '455532123266'; result = [4, 5, [5, 5, 3, 2, 1, 2, 3, 2], 6, [6]]

string = '123456789'; result = [1, 2, 3, 4, 5, 6, 7, 8, 9]

My code is as follows:

def numbers_in_lists(s):
    n=len(s)
    p=[]
    i=0
    while i<=n-1:
        p.append(int(s[i]))
        i=i+1

    r=[p[0]]    
    if p[1]<=p[0]:
        r.append([p[1]])
    else:
        r.append(p[1])
    if n<=2:
        return r
    j=2
    while j<=n-1:
        if p[j]<=p[j-1]:
            if p[j-1]<=p[j-2]:
                r[-1].append(p[j])
            else:
                r.append(p[j])
        else:
            if p[j]<=p[j-2]:
                r[-1].append(p[j])
            else:
                r.append(p[j])
        j=j+1
    return r

When I tried to run print (numbers_in_lists('543987')), I got this:

Traceback (most recent call last):
  File "Lesson14Quiz3.py", line 33, in <module>
    print (numbers_in_lists(string))
  File "Lesson14Quiz3.py", line 20, in numbers_in_lists
    r[-1].append(p[j])
AttributeError: 'int' object has no attribute 'append'

The problem seems to be with this line: r[-1].append(p[j]). But I think when the previous conditions are satisfied, r[-1] should not be an integer, but a list.

Upvotes: 1

Views: 1880

Answers (2)

Austin
Austin

Reputation: 26039

r is a list. So, you can safely do r.append(p[1]). But r[len(r)-1] is an element in the list r at position len(r)-1 which is an integer, not a list. r[len(r)-1].append(p[j]) is performing append on int which is not possible. Hence this error.

For example: Consider r = [ 1, 2, 3, 4, 5]

>>> r.append(6)
 [1, 2, 3, 4, 5, 6]

>>> r[5].append(7) # here r[5] is 6 which is an integer
AttributeError: 'int' object has no attribute 'append'

With your code, the input s ='4655....' gives you this error. Because you append 4,then you see 6 which is greater so you add it as next element. Then you see 5. Your code will add it as an element. Then again a 5 comes. Here is the problem. At this step, p[j]<=p[j-1] (5<=5) and p[j-1]<=p[j-2] (5<=6) are true. So, r[-1].append(p[j]) is done where r[-1] is 5 (append operation on 5 which is actually an integer).

Please do a traverse through your code. There is logical error, which results in appending to an integer.

Two problems:

Problem 1: In your code, within the while j<=n-1: loop, you are not creating any sublists in the list r. When p[j]<=p[j-1] is true and p[j-1]<=p[j-2] is false, actually you need to create a sublist with the item p[j]. You instead added p[j] as simply an element in the list.

Problem 2: Your code only checks for last three elements in list. This causes a new item to insert as a new element in the list when it should actually be an element in the sublist.

SOLUTION:

def numbers_in_lists(s):
    n=len(s)
    p=[]
    i=0
    while i<=n-1:
        p.append(int(s[i]))
        i=i+1

    r=[p[0]]    
    if p[1]<=p[0]:
        r.append([p[1]])
        k = p[1]
    else:
        r.append(p[1])
        k = -1
    if n<=2:
        return r
    j=2
    while j<=n-1:
        if p[j]<=p[j-1]:
            if p[j-1]<=p[j-2] or p[j]<=k:
                r[-1].append(p[j])
            else:
                r.append([p[j]])
                k = p[j]
        else:
            if p[j]<=p[j-2] or p[j]<=k:
                r[-1].append(p[j])
            else:
                r.append(p[j])
        j=j+1
    return r

Outputs:

'543987' ->  [5, [4, 3], 9, [8, 7]]

'987654321' ->  [9, [8, 7, 6, 5, 4, 3, 2, 1]]

'455532123266'  ->  [4, 5, [5, 5, 3, 2, 1, 2, 3, 2], 6, [6]]

'123456789'  ->  [1, 2, 3, 4, 5, 6, 7, 8, 9]

Upvotes: 4

E. Ducateme
E. Ducateme

Reputation: 4248

This line of code:

r[len(r)-1].append(p[j])

breaks down to this:

r: your overall list
len(r): an integer value based on calculation of the length of r 
-1: also an integer value

Let's pretend len(r) is 5.

Thus 5 - 1 is equal to 4.

r[4] uses Python indexing to identify a specific element in the list r. Specifically, the element at position 4, starting by counting at index 0.

If the element at position 4 is a number like an integer (rather than a sublist), then Python cannot append anything to the number, cause numbers do not have an .append() method.

Example:

Presuming we have a list that looks like:

r = [7, 13, 42] 

And we want to append a 99.

>>> r.append(99)
[7, 13, 42, 99]

But if we index to one of the integers within r, as opposed to a sublist within r, we get the error.

>>> r[1].append(99)     # r[1] is the value 13.
AttributeError: 'int' object has no attribute 'append'

Lastly, if the item we are indexing to is a sublist, then append() will work just fine.

# presume r now equals: [7, 13, 42, 99, [1]]
#    and we want to append a 1337
>>> r[-1].append(1337)     # r[-1] is the last value and is a sublist
[7, 13, 42, 99, [1, 1337]]

Possible solution:

This may help solve your problem and may make it easier to troubleshoot the code.

def numbers_in_lists(s):
    # use a list comprehension to simplify the process of making a list of
    #     integers
    p = [int(x) for x in s]

    # set two sentinel values to help control the code logic/decisions
    flag = False
    previous_high = 0

    # create an empty list
    r = []

    # iterate over all the digits...
    for num in p:

        # the code logic is broken into three tests 
        if num <= previous_high and not flag:
            # if flag is False create a sublist
            r.append([num])
            flag = True

        elif num < previous_high and flag:
            # if flag is True append to a sublist we previously created
            r[-1].append(num) 

        elif num > previous_high:
            # Otherwise, append to the main list again   
            r.append(num)
            previous_high = num
            flag = False

    return r

Sample outputs (using the strings the OP provided):

>>> numbers_in_list('543987')
[5, [4, 3], 9, [8, 7]]

>>> numbers_in_list('987654321')
[9, [8, 7, 6, 5, 4, 3, 2, 1]]

>>> numbers_in_list('455532123266')
[4, 5, [5, 3, 2, 1, 2, 3, 2], 6, [6]]

>>> numbers_in_list('123456789')
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Upvotes: 4

Related Questions