6

Write a function that accepts an input list and returns a new list which contains only the unique elements (Elements should only appear one time in the list and the order of the elements must be preserved as the original list. ).

def unique_elements (list):
    new_list = []
    length = len(list)
    i = 0
    while (length != 0):
        if (list[i] != list [i + 1]):
            new_list.append(list[i])
        i = i + 1
        length = length - 1
    '''new_list = set(list)'''
    return (new_list)

#Main program
n = int(input("Enter length of the list: "))
list = []
for i in range (0, n):
    item = int(input("Enter only integer values: "))
    list.append(item)
print ("This is your list: ", list)
result = unique_elements (list)
print (result)

I am stuck with this error:

IndexError: list index out of range

Cleb
  • 25,102
  • 20
  • 116
  • 151
Karan Thakkar
  • 1,007
  • 5
  • 24
  • 41
  • 4
    Just a quick note, `list` is a keyword – Obsidian Feb 21 '16 at 07:13
  • @Obsidian no `list` is not a keyword – helloV Feb 21 '16 at 07:17
  • 1
    List is the name of a builtin. You can redefine it, but it is not recommended. – Tom Karzes Feb 21 '16 at 07:19
  • 1
    @helloV Sorry. Meant a builtin function – Obsidian Feb 21 '16 at 07:20
  • 3
    Your list index range error is due to the fact that `i` is being iterated over all element indices, so when it's on the last element, `i+1` will be out of bounds. But a bigger problem is that you're only checking adjacent elements for duplicates. What if your list is `[1, 2, 1]`? Your algorithm will return all three elements, which I don't believe you want. – Tom Karzes Feb 21 '16 at 07:22
  • Thanks a ton folks. All these comments are of great help and addition to my knowledge. – Karan Thakkar Feb 21 '16 at 09:44
  • Found an easier approach for people on Python 3.7 [here](https://stackoverflow.com/questions/12897374/get-unique-values-from-a-list-in-python) – Kailas Dec 31 '20 at 03:50

10 Answers10

18

This is the simplest way to do it:

a = [1, 2, 2, 3]
b = []
for i in a:
    if i not in b:
        b.append(i)
print (b)
[1, 2, 3]
Joe T. Boka
  • 6,554
  • 6
  • 29
  • 48
  • The question is what is the issue with the code? Not asking a new solution. – helloV Feb 21 '16 at 07:23
  • 1
    @helloV my understanding of the OP is to come up with an answer to the problem which is: Write a function that accepts an input list and returns a new list which contains only the unique elements (Elements should only appear one time in the list and the order of the elements must be preserved as the original list. ). – Joe T. Boka Feb 21 '16 at 07:27
3

The problem with your code is that you are looping length times but checking list[i] with list[i+1], thus accessing an element past the end of the input list (e.g. in a list with 6 elements there are 6-1=5 pairs of consecutive elements).

A second issue with your code is that an input with only one element [1] should give as output [1] even if this element is not different from any other. The input text means you should remove elements that are equal to other elements already present, not that you should keep elements that are different from the next one.

Another issue is that you're only checking for consecutive duplicates i.e. given the input list [1, 2, 1, 2] your logic wouldn't detect any duplication... looks like the exercise instead requires in this case as output of [1, 2].

A trace for a simple algorithm to do this is

for each element in input
   if the element has not been included in output
       add the element to the end of output

Note also that to check if an element is present in a list Python provides the in operator (e.g. if x in output: ...) that can save you an explicit loop for that part.

As a side note naming an input parameter list is considered bad practice in Python because list is the name of a predefined function and your parameter is hiding it.

6502
  • 112,025
  • 15
  • 165
  • 265
2

O(n) solution without using a set:

>>> from collections import Counter, OrderedDict
>>> class OrderedCounter(Counter, OrderedDict):
...     pass
... 
>>> lst = [1, 2, 2, 3, 4, 5, 4]
>>> [x for x,c in OrderedCounter(lst).items() if c==1]
[1, 3, 5]
timgeb
  • 76,762
  • 20
  • 123
  • 145
2
l = [1, 2, 2, 3,4,5,6,5,7,8]
myList = []
[ myList.append(item) for item in l if item not in myList]
print(myList)
1

One line implementation:

list = [100, 3232, 3232, 3232, 57, 57, 90]
new_list = []

[new_list.append(x) for x in list if x not in new_list]

print(new_list)

Prints:

[100, 3232, 57, 90]
George Petrov
  • 2,729
  • 1
  • 13
  • 20
  • 4
    It's a bad idea to use a list comprehension just to avoid the extra lines of a regular `for` loop and `if` statement. You build an extra list of `None` values, only to throw it away again. – Blckknght Feb 21 '16 at 08:02
1

The problematic line is > if (list[i] != list [i + 1]): < (6th line in your code).

Reason: Imagine your list has got 4 elements.

Eg: mylist = [ 1, 2,2,3].

mylist[i] != mylist [i + 1]

In the last iteration 'i' will be 4 , so i + 1 will be 5.

There is no such 5th index in that list, because list indexes are counted from zero.

mylist[0] = 1

mylist[1] = 2

mylist[2] = 2

mylist[3] = 3

mylist[4] = No Index

mylist[5] = No Index

    def unique_elements (list):
        new_list = []

   # Replace the while with a for loop** 

        for i in list:
          if i not in new_list:
            new_list.append(i)


        return (new_list)

    #Main program
    n = int(input("Enter length of the list: "))
    list = []
    for i in range (0, n):
        item = int(input("Enter only integer values: "))
        list.append(item)
    print ("This is your list: ", list)
    result = unique_elements (list)
    print (result)
Fuji Komalan
  • 1,979
  • 16
  • 25
0

Use of collections is best IMO, Accepted answer is simplest, Adding another approach using dict where you can check frequency as well,


text = [100, 3232, 3232, 3232, 57, 57, 90]
# create empty dictionary
freq_dict = {}
 
# loop through text and count words
for word in text:
    # set the default value to 0
    freq_dict.setdefault(word, 0)
    # increment the value by 1
    freq_dict[word] += 1
 
unique_list = [key for key,value in freq_dict.items()]

print(unique_list )

print(freq_dict )
[100, 3232, 57, 90]
{100: 1, 3232: 3, 57: 2, 90: 1}

[Program finished] 

You can also print by values based on requirements.

Subham
  • 397
  • 1
  • 6
  • 14
0

So if you are at the last element, then if (list[i] != list [i + 1]): will try to take a value out of the list which is not present there and that is why the error is showing that the list is out of range.

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31408665) – Peter Mar 31 '22 at 17:23
-2

You can work this out using sets and set comprehension syntax is in most cases overlooked. Just as lists sets can also be generated using comprehension.

elements = [1, 2, 3, 3, 5, 7, 8, 7, 9]
unique_elements = {element for element in elements}
print(unique_elements)
Nelson M
  • 1,658
  • 4
  • 13
  • 19
-2

Found an easier approach for people on Python 3.7.

Using a dictionary:

list(dict.fromkeys(mylist))
ppwater
  • 2,315
  • 4
  • 15
  • 29
Kailas
  • 1