I have two unsorted lists of integers without duplicates both of them contain the same elements but not in the same order and I want to find the indices of the common elements between the two lists in lowest time complexity. For example
a = [1, 8, 5, 3, 4]
b = [5, 4, 1, 3, 8]
the output should be :
list1[0] With list2[2]
list1[1] With list2[4]
list1[2] With list2[0]
and so on
I have thought of using set. intersection and then find the index using the 'index' function but I didn't know how to print the output in a right way
this is what I've tried
b = set(list1).intersection(list2)
ina = [list1.index(x) for x in b]
inb = [list2.index(x) for x in b]
print (ina , inb )
To find them in linear time you should use some kind of hashing. The easiest way in Python is to use a dict:
list1 = [1, 8, 5, 3, 4]
list2 = [5, 4, 1, 3, 8]
common = set(list1).intersection(list2)
dict2 = {e: i for i, e in enumerate(list2) if e in common}
result = [(i, dict2[e]) for i, e in enumerate(list1) if e in common]
The result will be
[(0, 2), (1, 4), (2, 0), (3, 3), (4, 1)]
You can use something like this to format and print it:
for i1, i2 in result:
print(f"list1[{i1}] with list2[{i2}]")
you get:
list1[0] with list2[2]
list1[1] with list2[4]
list1[2] with list2[0]
list1[3] with list2[3]
list1[4] with list2[1]
Create a dictionary that maps elements of one list to their indexes. Then update it to have the indexes of the corresponding elements of the other list. Then any element that has two indices is in the intersection.
intersect = {x: [i] for i, x in enumerate(list1)}
for i, x in enumerate(list2):
if x in intersect:
intersect[x].append(i)
for l in intersect.values():
if len(l) == 2:
print(f'list1[{l[0]}] with list2[{l[1]}]')
a = [1, 8, 5, 3, 4]
b = [5, 4, 1, 3, 8]
e2i = {e : i for (i, e) in enumerate(b)}
for i, e in enumerate(a):
if e in e2i:
print('list1[%d] with list2[%d]' % (i, e2i[e]))
Building on the excellent answers here, you can squeeze a little more juice out of the lemon by not bothering to record the indices of a. (Those indices are just 0 through len(a) - 1 anyway and you can add them back later if needed.)
e2i = {e : i for (i, e) in enumerate(b)}
output = [e2i.get(e) for e in enumerate(a)]
output
# [2, 4, 0, 3, 1]
With len(a) == len(b) == 5000 on my machine this code runs a little better than twice as fast as Björn Lindqvist's code (after I modified his code to store the output rather than print it).
How do I remove an element from a list by index?
I found list.remove(), but this slowly scans the list for an item by value.
Use del and specify the index of the element you want to delete:
>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> del a[-1]
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8]
Also supports slices:
>>> del a[2:4]
>>> a
[0, 1, 4, 5, 6, 7, 8, 9]
Here is the section from the tutorial.
You probably want pop:
a = ['a', 'b', 'c', 'd']
a.pop(1)
# now a is ['a', 'c', 'd']
By default, pop without any arguments removes the last item:
a = ['a', 'b', 'c', 'd']
a.pop()
# now a is ['a', 'b', 'c']
Like others mentioned pop and del are the efficient ways to remove an item of given index. Yet just for the sake of completion (since the same thing can be done via many ways in Python):
Using slices (this does not do in place removal of item from original list):
(Also this will be the least efficient method when working with Python list, but this could be useful (but not efficient, I reiterate) when working with user defined objects that do not support pop, yet do define a __getitem__ ):
>>> a = [1, 2, 3, 4, 5, 6]
>>> index = 3 # Only positive index
>>> a = a[:index] + a[index+1 :]
# a is now [1, 2, 3, 5, 6]
Note: Please note that this method does not modify the list in place like pop and del. It instead makes two copies of lists (one from the start until the index but without it (a[:index]) and one after the index till the last element (a[index+1:])) and creates a new list object by adding both. This is then reassigned to the list variable (a). The old list object is hence dereferenced and hence garbage collected (provided the original list object is not referenced by any variable other than a).
This makes this method very inefficient and it can also produce undesirable side effects (especially when other variables point to the original list object which remains un-modified).
Thanks to #MarkDickinson for pointing this out ...
This Stack Overflow answer explains the concept of slicing.
Also note that this works only with positive indices.
While using with objects, the __getitem__ method must have been defined and more importantly the __add__ method must have been defined to return an object containing items from both the operands.
In essence, this works with any object whose class definition is like:
class foo(object):
def __init__(self, items):
self.items = items
def __getitem__(self, index):
return foo(self.items[index])
def __add__(self, right):
return foo( self.items + right.items )
This works with list which defines __getitem__ and __add__ methods.
Comparison of the three ways in terms of efficiency:
Assume the following is predefined:
a = range(10)
index = 3
The del object[index] method:
By far the most efficient method. It works will all objects that define a __del__ method.
The disassembly is as follows:
Code:
def del_method():
global a
global index
del a[index]
Disassembly:
10 0 LOAD_GLOBAL 0 (a)
3 LOAD_GLOBAL 1 (index)
6 DELETE_SUBSCR # This is the line that deletes the item
7 LOAD_CONST 0 (None)
10 RETURN_VALUE
None
pop method:
It is less efficient than the del method and is used when you need to get the deleted item.
Code:
def pop_method():
global a
global index
a.pop(index)
Disassembly:
17 0 LOAD_GLOBAL 0 (a)
3 LOAD_ATTR 1 (pop)
6 LOAD_GLOBAL 2 (index)
9 CALL_FUNCTION 1
12 POP_TOP
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
The slice and add method.
The least efficient.
Code:
def slice_method():
global a
global index
a = a[:index] + a[index+1:]
Disassembly:
24 0 LOAD_GLOBAL 0 (a)
3 LOAD_GLOBAL 1 (index)
6 SLICE+2
7 LOAD_GLOBAL 0 (a)
10 LOAD_GLOBAL 1 (index)
13 LOAD_CONST 1 (1)
16 BINARY_ADD
17 SLICE+1
18 BINARY_ADD
19 STORE_GLOBAL 0 (a)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
None
Note: In all three disassembles ignore the last two lines which basically are return None. Also the first two lines are loading the global values a and index.
pop is also useful to remove and keep an item from a list. Where del actually trashes the item.
>>> x = [1, 2, 3, 4]
>>> p = x.pop(1)
>>> p
2
If you want to remove elements at specific positions in a list, like the 2nd, 3rd and 7th elements, you can't use
del my_list[2]
del my_list[3]
del my_list[7]
Since after you delete the second element, the third element you delete actually is the fourth element in the original list. You can filter the 2nd, 3rd and 7th elements in the original list and get a new list, like below:
new_list = [j for i, j in enumerate(my_list) if i not in [2, 3, 7]]
It has already been mentioned how to remove a single element from a list and which advantages the different methods have. Note, however, that removing multiple elements has some potential for errors:
>>> l = [0,1,2,3,4,5,6,7,8,9]
>>> indices=[3,7]
>>> for i in indices:
... del l[i]
...
>>> l
[0, 1, 2, 4, 5, 6, 7, 9]
Elements 3 and 8 (not 3 and 7) of the original list have been removed (as the list was shortened during the loop), which might not have been the intention. If you want to safely remove multiple indices you should instead delete the elements with highest index first, e.g. like this:
>>> l = [0,1,2,3,4,5,6,7,8,9]
>>> indices=[3,7]
>>> for i in sorted(indices, reverse=True):
... del l[i]
...
>>> l
[0, 1, 2, 4, 5, 6, 8, 9]
Use the del statement:
del listName[-N]
For example, if you want to remove the last 3 items, your code should be:
del listName[-3:]
For example, if you want to remove the last 8 items, your code should be:
del listName[-8:]
This depends on what you want to do.
If you want to return the element you removed, use pop():
>>> l = [1, 2, 3, 4, 5]
>>> l.pop(2)
3
>>> l
[1, 2, 4, 5]
However, if you just want to delete an element, use del:
>>> l = [1, 2, 3, 4, 5]
>>> del l[2]
>>> l
[1, 2, 4, 5]
Additionally, del allows you to use slices (e.g. del[2:]).
Generally, I am using the following method:
>>> myList = [10,20,30,40,50]
>>> rmovIndxNo = 3
>>> del myList[rmovIndxNo]
>>> myList
[10, 20, 30, 50]
Yet another way to remove an element(s) from a list by index.
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# remove the element at index 3
a[3:4] = []
# a is now [0, 1, 2, 4, 5, 6, 7, 8, 9]
# remove the elements from index 3 to index 6
a[3:7] = []
# a is now [0, 1, 2, 7, 8, 9]
a[x:y] points to the elements from index x to y-1. When we declare that portion of the list as an empty list ([]), those elements are removed.
You could just search for the item you want to delete. It is really simple.
Example:
letters = ["a", "b", "c", "d", "e"]
letters.remove(letters[1])
print(*letters) # Used with a * to make it unpack you don't have to (Python 3.x or newer)
Output: a c d e
Use the following code to remove element from the list:
list = [1, 2, 3, 4]
list.remove(1)
print(list)
output = [2, 3, 4]
If you want to remove index element data from the list use:
list = [1, 2, 3, 4]
list.remove(list[2])
print(list)
output : [1, 2, 4]
As previously mentioned, best practice is del(); or pop() if you need to know the value.
An alternate solution is to re-stack only those elements you want:
a = ['a', 'b', 'c', 'd']
def remove_element(list_,index_):
clipboard = []
for i in range(len(list_)):
if i is not index_:
clipboard.append(list_[i])
return clipboard
print(remove_element(a,2))
>> ['a', 'b', 'd']
eta: hmm... will not work on negative index values, will ponder and update
I suppose
if index_<0:index_=len(list_)+index_
would patch it... but suddenly this idea seems very brittle. Interesting thought experiment though. Seems there should be a 'proper' way to do this with append() / list comprehension.
pondering
l - list of values; we have to remove indexes from inds2rem list.
l = range(20)
inds2rem = [2,5,1,7]
map(lambda x: l.pop(x), sorted(inds2rem, key = lambda x:-x))
>>> l
[0, 3, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
It doesn't sound like you're working with a list of lists, so I'll keep this short. You want to use pop since it will remove elements not elements that are lists, you should use del for that. To call the last element in python it's "-1"
>>> test = ['item1', 'item2']
>>> test.pop(-1)
'item2'
>>> test
['item1']
Or if multiple indexes should be removed:
print([v for i,v in enumerate(your_list) if i not in list_of_unwanted_indexes])
Of course then could also do:
print([v for i,v in enumerate(your_list) if i != unwanted_index])
You can use either del or pop to remove element from list based on index. Pop will print member it is removing from list, while list delete that member without printing it.
>>> a=[1,2,3,4,5]
>>> del a[1]
>>> a
[1, 3, 4, 5]
>>> a.pop(1)
3
>>> a
[1, 4, 5]
>>>
One can either use del or pop, but I prefer del, since you can specify index and slices, giving the user more control over the data.
For example, starting with the list shown, one can remove its last element with del as a slice, and then one can remove the last element from the result using pop.
>>> l = [1,2,3,4,5]
>>> del l[-1:]
>>> l
[1, 2, 3, 4]
>>> l.pop(-1)
4
>>> l
[1, 2, 3]
So I need to have a code that checks one integer, and checks if the integer after it is the same value. If so, it will add the value to x.
input1 = [int(i) for i in str(1234441122)]
x= 0
So my code currently gives the result [1, 2, 3, 4, 4, 4, 1, 1 ,2 ,2]. I want it to give the result of x = 0+4+4+1+2.
I do not know any way to do that.
The following will work. Zip together adjacent pairs and only take the first elements if they are the same as the second ones:
>>> lst = [1, 2, 3, 4, 4, 4, 1, 1, 2, 2]
>>> sum(x for x, y in zip(lst, lst[1:]) if x == y)
11
While this should be a little less [space-]efficent in theory (as the slice creates an extra list), it still has O(N) complexity in time and space and is well more readable than most solutions based on indexed access. A tricky way to avoid the slice while still being concise and avoiding any imports would be:
>>> sum((lst[i] == lst[i-1]) * lst[i] for i in range(1, len(lst))) # Py2: xrange
11
This makes use of the fact that lst[i]==lst[i-1] will be cast to 0 or 1 appropriately.
Another way using itertools.groupby
l = [1, 2, 3, 4, 4, 4, 1, 1 ,2 ,2]
from itertools import groupby
sum(sum(g)-k for k,g in groupby(l))
#11
You can try this:
s = str(1234441122)
new_data = [int(a) for i, a in enumerate(s) if i+1 < len(s) and a == s[i+1]]
print(new_data)
final_data = sum(new_data)
Output:
[4, 4, 1, 2]
11
No need for that list. You can remove the "non-repeated" digits from the string already:
>>> n = 1234441122
>>> import re
>>> sum(map(int, re.sub(r'(.)(?!\1)', '', str(n))))
11
You are simply iterating on string and converting character to integer. You need to iterate and compare to next character.
a = str(1234441122)
sum = 0
for i,j in enumerate(a[:-1]):
if a[i] == a[i+1]:
sum+=int(a[i])
print(sum)
Output
11
Try this one too:
input1 = [int(i) for i in str(1234441122)]
x= 0
res = [input1[i] for i in range(len(input1)-1) if input1[i+1]==input1[i]]
print(res)
print(sum(res))
Output:
[4, 4, 1, 2]
11
Here's a slightly more space efficient version of #schwobaseggl's answer.
>>> lst = [1, 2, 3, 4, 4, 4, 1, 1, 2, 2]
>>> it = iter(lst)
>>> next(it) # throw away first value
>>> sum(x for x,y in zip(lst, it) if x == y)
11
Alernatively, using an islice from the itertools module is equivalent but looks a bit nicer.
>>> from itertools import islice
>>> sum(x for x,y in zip(lst, islice(lst, 1, None, 1)) if x == y)
11
Let's say I have two lists list1 and list2 as:
list1 = [ 3, 4, 7 ]
list2 = [ 5, 2, 3, 5, 3, 4, 4, 9 ]
I want to find the count of the elements of list1 which are present in list2.
Expected output is 4 because 3 and 4 from list1 are appearing twice in list2. Hence, total count is as 4.
Use list comprehension and check if element exists
c = len([i for i in list2 if i in list1 ])
Better one from #Jon i.e
c = sum(el in list1 for el in list2)
Output : 4
You may use sum(...) to achieve this with the generator expression as:
>>> list1 = [ 3, 4, 7 ]
>>> list2 = [ 5, 2, 3, 5, 3, 4, 4, 9 ]
# v returns `True`/`False` and Python considers Boolean value as `0`/`1`
>>> sum(x in list1 for x in list2)
4
As an alternative, you may also use Python's __contains__'s magic function to check whether element exists in the list and use filter(..) to filter out the elements in the list not satisfying the "in" condition. For example:
>>> len(list(filter(list1.__contains__, list2)))
4
# Here "filter(list(list1.__contains__, list2))" will return the
# list as: [3, 3, 4, 4]
For more details about __contains__, read: What does __contains__ do, what can call __contains__ function?.
You can iterate first list and add occurences of a given number to a sum using count method.
for number in list1:
s += list2.count(number);
You can use collections.Counter here, so a naive and rather ugly implementation first (mine).
list1 = [ 3, 4, 7 ]
list2 = [ 5, 2, 3, 5, 3, 4, 4, 9 ]
from collections import Counter
total = 0
c = Counter(list2)
for i in list1:
if c[i]:
total += c[i]
This doesn't take into account what happens if you've got duplicates in the first list (HT Jon), and a much more elegant version of this would be:
counter = Counter(list2)
occurrences = sum(counter[v] for v in set(list1))
I have to compare 2 lists, if element of list a is present in list b, then the element of list b is to print.
a = [1, 3, 2, 1, 3]
b = [2, 2, 1, 1, 1, 4, 2, 3]
ans = [1, 1, 1, 3, 2, 2, 2, 1, 1, 1, 3]
I may get the answer by using 2 for loops like:
for a_ in a:
for b_ in b:
if a_ == b_:
print b_
op: 1 1 1 3 2 2 2 1 1 1 3
But I don't want to use 2 for loops. How can I do that with a single loop?
Use collections.Counter to count for you:
from collections import Counter
c = Counter(b)
ans = []
for x in a:
ans += [x]*c.get(x,0)
This is one potential way (a bit messy), just posting it since it turns out Fabricator didn't end up with the correct result.
[item for sublist in ([i] * b.count(i) for i in a) for item in sublist]
Basically, the ([i] * b.count(i) for i in a) part builds the list, but it ends up as a list of lists, so then I did the [item for sublist in list for item in sublist] thing to flatten the list.
It's probably a bit similar to the answer by zondo but this keeps it as a list of numbers instead of a string.
print(" ".join(str(x) for x in a for _ in range(b.count(x))))
This, should be work:
for a_ in a:
if b.count(a_) :
ans+=((str(a_)+' ')*b.count(a_)).strip().split(' ')
list.count(x) count the number of occourrences of x in list.
you can print n times a string simply: *'mystring'times
Hope I helped you!