Not empty list is out of index on list[0] - python

I'm doing this problem on Leetcode: https://leetcode.com/problems/merge-two-sorted-lists/description/
I came up with this solution:
class Solution(object):
def mergeTwoLists(self, list1, list2):
x = list1
y = list2
listx = []
listy = []
while x != None and y != None:
if x != None:
listx.append(x.val)
x = x.next
if y != None:
listy.append(y.val)
y = y.next
listz = []
listz.extend(listx)
listz.extend(listy)
listz.sort()
resultlist = []
for i in range(len(listz)):
resultlist.append(ListNode(listz[i]))
for x in reversed(range(len(resultlist)-1)):
resultlist[x].next = resultlist[x+1]
result = resultlist[0]
return result
Explanation of the code:
from the input(ListNode) create two lists
merge the lists into one list and sort it
create a list of ListNodes(resultlist) "create nodes"
create the return ListNode splicing all the nodes from result nodes
This code should work but when I try to run it, it gives me this error:
IndexError: list index out of range result = resultlist[0]"
even though the list isn't empty and it contains an element on the index 0.
How can I solve this?

This exercise is all about how you navigate a singly linked list. Building lists and reconstructing the linked list is not a great idea.
The problem in the code shown in the question comes about due to lack of checking against edge cases.
This will perform better and will be more robust:
class Solution():
def mergeTwoLists(self, list1, list2):
cln = ListNode()
dln = cln
while list1 and list2:
if list1.val < list2.val:
cln.next = list1
list1, cln = list1.next, list1
else:
cln.next = list2
list2, cln = list2.next, list2
if list1 or list2:
cln.next = list1 if list1 else list2
return dln.next

If both list1 and list2 are empty then your resultlist will be empty too (there will be no element at index 0) so check at the start of your method if both lists are empty if yes then return list1 or list2
if not (list1 and list2): return list1
and I think your result will some fail test cases.
Please check for edge cases and you can make this code more simple if you use link list and do not use python list
All the best!!!

Related

Write optimized code which takes following two list of dictionaries as input and gives output as final_result.I have solved it but I want to optimized

Inputs:
list1 = [{'item_type':1,'value':55, 'title':'abc'},{'item_type':2,'value':43, 'title':'def'},{'item_type':3,'value':35, 'title':'ghi'}]
list2 = [{'item_type':2,'value':13, 'title':'jkl'},{'item_type':3,'value':85, 'title':'mno'}]
Challange1:
If the item_type is present in list2 then that should take the priority.
expected result:
final_result = [{'item_type':1,'value':55, 'title':'abc'},{'item_type':2,'value':13, 'title':'jkl'},{'item_type':3,'value':85, 'title':'mno'}]
Challange2:
It should merge list1 and list2 based on unique item_type and keep the higher 'value' dictionary.
expected result:
final_result = [{'item_type':1,'value':55, 'title':'abc'},{'item_type':2,'value':43, 'title':'def'},{'item_type':3,'value':85, 'title':'mno'}]
.
I have solved both the challenges but I want to optimized this code using list comprehensive, lambda .. please help me...
this is my code
Challange1:
final_result = []
list1 = [{'item_type':1,'value':55, 'title':'abc'},{'item_type':2,'value':43, 'title':'def'},{'item_type':3,'value':35, 'title':'ghi'}]
list2 = [{'item_type':2,'value':13, 'title':'jkl'},{'item_type':3,'value':85, 'title':'mno'}]
for i in range(len(list1)):
for j in range(len(list2)):
if list1[i]['item_type'] == list2[j]['item_type']:
if list1[i]['item_type'] < list2[j]['item_type']:
final_result.append(list1[i])
else:
final_result.append(list2[j])
break
else:
final_result.append(list1[i])
print(final_result)
Challange2:
final_result = []
list1 = [{'item_type':1,'value':55, 'title':'abc'},{'item_type':2,'value':43, 'title':'def'},{'item_type':3,'value':35, 'title':'ghi'}]
list2 = [{'item_type':2,'value':13, 'title':'jkl'},{'item_type':3,'value':85, 'title':'mno'}]
for i in range(len(list1)):
for j in range(len(list2)):
if list1[i]['item_type'] == list2[j]['item_type']:
if list1[i]['value'] > list2[j]['value']:
final_result.append(list1[i])
else:
final_result.append(list2[j])
break
else:
final_result.append(list1[i])
print(final_result)
So you want to use list (or other) comprehension.
From Python 3.7, dictionaries are officially ordered. You can (1) concatenate the lists and sort the items if necessary, (2) put the items into a dictionary with item_type as their keys, and (3) convert values in the dictionary back to the list, to get the desired results.
Challange1:
final_result = [*{item['item_type']: item for item in list1 + list2}.values()]
Challange2:
final_result = [*{item['item_type']: item for item in sorted(list1 + list2, key=lambda item: (item['item_type'], item['value']))}.values()]
According the stated information in the question.
The first challenge is to union the two lists with a priority to the second list. A quick solution can be:
list1 = [
{'item_type':1,'value':55, 'title':'abc'},
{'item_type':2,'value':43, 'title':'def'},
{'item_type':3,'value':35, 'title':'ghi'}
]
list2 = [
{'item_type':2,'value':13, 'title':'jkl'},
{'item_type':3,'value':85, 'title':'mno'}
]
final_result = [
item for item in list1
if item['item_type'] not in
[item['item_type'] for item in list2]
] + list2
print(final_result)
The second challenge is to union the two lists with a priority to the value. A quick solution can be:
list1 = [
{'item_type':1,'value':55, 'title':'abc'},
{'item_type':2,'value':43, 'title':'def'},
{'item_type':3,'value':35, 'title':'ghi'}
]
list2 = [
{'item_type':2,'value':13, 'title':'jkl'},
{'item_type':3,'value':85, 'title':'mno'}
]
isNotIn = lambda item, L: len(
[el['item_type'] for el in L
if item['item_type'] == el['item_type']]
) == 0
isHigher = lambda item, L: len(
[el['item_type'] for el in L
if item['item_type'] == el['item_type'] and
item['value'] > el['value']]
) > 0
final_result = [el for el in list1 if (isNotIn(el, list2) or isHigher(el, list2))] + \
[el for el in list2 if (isNotIn(el, list1) or isHigher(el, list1))]
print(final_result)

How to make nested for loops using nested try/except to check if there is a list to iterate?

How can I use try in nested for loops, so when my function would not have list of elements to iterate through, than it would go for the next loop that is nested. So something like this:
value = []
list1 = None
list2 = [1,2,3]
list3 = [1,2,3]
try:
for i in list1:
for j in list2:
for k in list3:
value.append(i+j+k)
except:
pass
Would change to this after the first try:
try:
for j in list2:
for k in list3:
value.append(j+k)
except:
pass
and if list2 was also None it would move to this:
try:
for k in list3:
value.append(k)
except:
pass
Do I have to repeat and make several nested loops with try:/except: or there is some way to make it look cleaner than the code below?
value = []
list1 = None
list2 = [1,2,3]
list3 = [1,2,3]
try:
for i in list1:
for j in list2:
for k in list3:
value.append(i+j+k)
except:
pass
try:
for j in list2:
for k in list3:
value.append(j+k)
except:
pass
try:
for k in list3:
value.append(k)
except:
pass
I'm not sure I understand what you want to do, but for your use case, I suggest you something like that:
from itertools import product
value = []
list1 = None
list2 = [1,2,3]
list3 = [1,2,3]
lists = [list1, list2, list3]
lists = [_list for _list in lists if _list is not None]
values = list(product(*lists))

Compare two lists element-wise and return the approximate value

I have two list as given below:
list1 = ['17_12_29', '17_08_04']
list2 = ['17_12_29_xyz','2017_12_29_abc', '17_08_04_mnp','17_08_04_mnp2',
'2017_08_04_def', '17_08_05_pqr']
I want to compare the two list element wise and expecting the result as given below:-
res = ['17_12_29_xyz','2017_12_29_abc', '17_08_04_mnp','17_08_04_mnp2','2017_08_04_def'].
We have different library are available to get the result, but my constraint to use python code only.
Using list comprehension and any
res = [x for x in list2 if any(y in x for y in list1)]
print(res) # Output: ['17_12_29_xyz', '2017_12_29_abc', '17_08_04_mnp', '17_08_04_mnp2', '2017_08_04_def']
This should work:
res=[]
list1 = ['17_12_29', '17_08_04']
list2 = ['17_12_29_xyz','2017_12_29_abc', '17_08_04_mnp','17_08_04_mnp2', '2017_08_04_def', '17_08_05_pqr']
for item in list2:
for j in list1:
if j in item:
res.append(item)
break
print(res)
You can check if a string exists within another string in python.
res = []
for s2 in list2:
for s1 in list1:
if s1 in s2:
res.append(s2)
You might wanna use in for comparison:
res=[]
for i in list1:
for j in list2:
if i in j:
res.append(j)

remove element from python list based on match from another list

I have list of s3 objects like this:
list1 = ['uid=123/2020/06/01/625e2ghvh.parquet','uid=876/2020/04/01/hgdshct7.parquet','uid=0987/2019/03/01/323dc.parquet']
list2 = ['123','876']
result_list = ['uid=0987/2019/03/01/323dc.parquet']
With out using any loop is there any efficient way to achieve this considering large no of elements in list1?
You could build a set from list2 for a faster lookup and use a list comprehension to check for membership using the substring of interest:
list1 = ['uid=123/2020/06/01/625e2ghvh.parquet','uid=876/2020/04/01/hgdshct7.parquet',
'uid=0987/2019/03/01/323dc.parquet']
list2 = ['123','876']
set2 = set(list2)
[i for i in list1 if i.lstrip('uid=').split('/',1)[0] not in set2]
# ['uid=0987/2019/03/01/323dc.parquet']
The substring is obtained through:
s = 'uid=123/2020/06/01/625e2ghvh.parquet'
s.lstrip('uid=').split('/',1)[0]
# '123'
This does the job. For different patterns though, or to also cover slight variations, you could go for a regex. For this example you'd need something like:
import re
[i for i in list1 if re.search(r'^uid=(\d+).*?', i).group(1) not in set2]
# ['uid=0987/2019/03/01/323dc.parquet']
This is one way to do it without loops
def filter_function(item):
uid = int(item[4:].split('/')[0])
if uid not in list2:
return True
return False
list1 = ['uid=123/2020/06/01/625e2ghvh.parquet','uid=876/2020/04/01/hgdshct7.parquet','uid=0987/2019/03/01/323dc.parquet']
list2 = [123, 876]
result_list = list(filter(filter_function, list1))
How about this one:
_list2 = [f'uid={number}' for number in list2]
result = [item for item in list1 if not any([item.startswith(i) for i in _list2])] # ['uid=0987/2019/03/01/323dc.parquet']

python 3.x append a list and remove item from old list

I was wondering if there was a way of shorting this code by using a list comprehension. I have tried to use them by every time the loop runs the last ltems in the loop are all I get. This is what I tried.
list2 = [i for i in list1 if i[0] == counter]
Here is the code I want to improve.
list1 = [(1,4),(2,5),(3,6),(4,6),(5,6),(6,7),(7,5),(8,6),(9,4)]
list2 = []
counter = 0
while counter != 10:
for i in list1:
if i[0] == counter:
list2.append(i)
for j in list2:
if j in list1:
list1.remove(j)
counter += 1
Thank you for any help
Edit. I should have given a bit more code here. There will be another list that will get filled by list2 when the counter == i[1]. I have used this list comprehension to replace the for loop used to remove items from list1
list1[:] = [i for i in list1 if i not in list2]
What I want to know is there any way of using a list comprehension (or something I have not seen before) that could get the for loop used to append the lists down to one line?
list1 = [(1,4),(2,5),(3,6),(4,6),(5,6),(6,7),(7,5),(8,6),(9,4)]
list2 = []
list3 = []
counter = 0
while counter != 10:
for i in list1:
if i[0] == counter:
list2.append(i)
for j in list2:
if j in list1:
list1.remove(j)
for x in list2:
if x[1] == counter:
list3.append(i)
for y in list3:
if y in list2:
list1.remove(y)
counter += 1
Try this one:
list1 = [(1,4),(2,5),(3,6),(4,6),(5,6),(6,7),(7,5),(8,6),(9,4)]
list2 = []
counter = 0
for counter, (x, y) in list(enumerate(list1)):
list2.append((x, y))
list1.remove((x, y))
As far as I can tell you're just copying the elements of list 1 into list 2. Then trying to remove all the elements of list 1 if they are in list 2. Technically this can be accomplished with the following
list1 = [(1,4),(2,5),(3,6),(4,6),(5,6),(6,7),(7,5),(8,6),(9,4)]
list2 = list1
list1 = []
But in the spirit of your question. The if statement you were using in your list comprehension is fine, but the value of counter is never incremented so you were always testing if i[0] == 0 which was never true.
If you are just trying to learn about how list comprehensions behave then what you were probably trying to accomplish can be done with the following
list1 = [(1,4),(2,5),(3,6),(4,6),(5,6),(6,7),(7,5),(8,6),(9,4)]
list2 = [list1[i] for i in range(len(list1))]
list1 = [val for val in list2 if val not in list1]
The first list comprehension is similar to using a counter. The second is a for each loop with a condition and is much more pythonic than the first. Not exactly sure what your intent is for this code, but hope this helps.
Okay I found an answer for my question if you use += instead of = in the list comprehension the list is append instead of replaced. Will only work if you declare the list before you run the comprehension. Thank you everyone for the answers.
list1 = [(1,4),(2,5),(3,6),(4,6),(5,6),(6,7),(7,5),(8,6),(9,4)]
list2 = []
list3 = []
counter = 0
while counter != 10:
list2 += [n for n in list1 if n[0] == counter]
list1 = [i for i in list1 if i not in list2]
list3 += [j for j in list2 if j[1] == counter]
list2 = [n for n in list2 if n not in list2]
counter += 1
The most performant way to do this that I can find is
list1.sort(lambda t: t[0], reverse=True)
list2 = []
for i in range(10):
while list1[-1][0] == i:
# grab all the items from list1 where x == i (in tuples (x, y) )
list2.append(list1.pop())
In this case a list comprehension is really not preferred.

Categories

Resources