Combine two lists for web scraping project - python

I have two lists: one is a basic list, with some being "new line" symbols (\n), and the other is a list of lists.
I would like to combine these, inserting the elements from the second list into the first list where \n appears so that the end result looks like this:
first_list = ['a','b','c',\n, 'd','e','f','g','h',\n]
second_list = [[1,2,3], [4,5,6]]
combine the two lists to get:
combined_list = ['a','b','c',1,2,3,'d','e','f','g','h',4,5,6].
I'm not quite sure why, but all of the \n's in the first list in my example have the same index position. Thus, when I try to loop through both lists to first find the position of the first \n and insert [1,2,3] at that point, it ends up inserting [1,2,3] at all positions where \n appears. I tried to simplify the problem here to make it easier to communicate, but the original problem comes from a web scraping project I am working on to retrieve information from Linkedin, with the elements in these lists being profile attributes for Linkedin users. Perhaps that could help to explain why the \n's all have the same index position?
Any help with how to properly combine these lists in the above way/explanations for why the \n's have the same index position would be greatly appreciated! Please let me know if I can provide any additional details. Thanks.

I know you mentioned there were some indexing issues with the \n values, but hopefully this sets you on the right track..it works for the simplified example data you provided (re-formatted to be proper considering the letters are not variables)
l1 = ['a','b','c','\n','d','e','f','g','h','\n']
l2 = [[1,2,3], [4,5,6]]
l3 = []
n_count = 0
for i,l in zip(range(len(l1)),l1):
if l != '\n':
l3.append(l)
elif l == '\n':
l3.extend(l2[n_count])
n_count += 1
print(l3)
['a', 'b', 'c', 1, 2, 3, 'd', 'e', 'f', 'g', 'h', 4, 5, 6]
if you can figure out the indexing issue this might help you with minor modifications

I assume that List1 and/or List2 can be continued.
The number of lists in List2 needs to be higher or equal than '\n's in List1.
List1 = ['a','b','c', '\n', 'd','e','f','g','h', '\n']
List2 = [[1,2,3], [4,5,6]]
# wanted = [a,b,c,1,2,3,d,e,f,g,h,4,5,6]
list3 = []
counter = 0
for val in List1:
if val == '\n':
[list3.append(elem) for elem in List2[counter]]
counter += 1
else:
list3.append(val)
print(list3)
['a', 'b', 'c', 1, 2, 3, 'd', 'e', 'f', 'g', 'h', 4, 5, 6]

Related

Manipulating a list of lists multiple times in order

I'm trying to alter a list of lists in multiple ways by using a function (as I will have more than one list of lists).
I know how to change something once, but how do I do more than that? I get the error:
AttributeError: 'int' object has no attribute 'insert'
I understand that the error essentially means (whatever I'm trying to use .insert() on is not a list) but I don't quite understand why it's not a list...
See my code below:
This works and gives me the desired output
list_of_list3 = [['a', 1], ['b', 2], ['c', 3]]
list_to_add = ['Z', 'X', 'Y']
for list_position in range(len(list_of_list3)):
original_list = list_of_list3[list_position]
element_to_add = list_to_add[list_position]
original_list.insert(0, element_to_add)
print(list_of_list3)
This will give me what I want:
[['Z', 'a', 1], ['X', 'b', 2], ['Y', 'c', 3]]
However, what I need is a function which does more than one thing at once. I am trying the code below:
def output_function(add_list, list_of_list):
for list_position in range(len(list_of_list)):
list_within_list = cleaned_list[list_position]
add_element1 = add_list[list_position] # The two lists will always have the same length
list_within_list = list_within_list.pop() # I want to remove the last element
list_with_element1 = list_within_list.insert(0, add_element1) # I then want to add a new element
list_with_new_list = list_with_element1.insert(0, ['Column1', 'Column2', 'Column3']) #Then I want to add a new list to the beginning of list of lists
new_elements = ['A', 'B', 'C']
original_list_list = [['D', 1, 2], ['E', 3, 4], ['F', 5, 6']
output_function(new_elements, original_list_list)
My desired output is (ultimately will turn this into a pandas df)
[['Column1', 'Column2', 'Column3'], ['A', 'D', 1], ['B','E', 3], ['C', 'F', 5]]
Any help is appreciated. Thanks!
I believe you are having some misunderstanding with the methods you are calling.
Your comments indicate you are going to throw away the popped element, but you are actually throwing away the list, and using the element instead.
These 2 lines:
list_within_list = list_within_list.pop() # I want to remove the last element
list_with_element1 = list_within_list.insert(0, add_element1) # I then want to add a new element
One way to accomplish:
list_with_element1 = list_within_list[:-1]
list_with_element1.insert(0, add_element1)

Count letter differences of two strings Python

I'm having some problems with an exercise about strings in python.
I have 2 different lists:
list1= "ABCDEFABCDEF"
and
list2= "AZBYCXDWEVFABCDEF"
I need to compare those 2 lists according to their position so the 1 letter together, then the 2...using the min length (so here length of list1) and store the letters in a new variable according to if they are different or the same.
identicals=[]
different=[]
I tried to code something and it seems to find the same ones, but doesn't work on the different ones since it copies them multiple times.
for x in list1:
for y in list2:
if list1>list2:
if x==y:
identicals.append(x)
if x!=y :
different.append(x)
if list2>list1:
if y==x:
identicals.append(y)
if y!=x:
different.append(y)
EDIT: Output result should be something like this:
identicals=['A']
different=["Z","B","Y","C","X","D","W","E","V",F","A"]
The thing is that the letter A is only shown on identicals but not in different even if F!=A.
You are getting unwanted duplicates because you have a nested pair of for loops, so each item in list2 get tested for every item in list1.
The key idea is to iterate over the two strings in parallel. You can do that with the built-in zip function, which yields a tuple of the corresponding items from each iterable you feed it, stopping as soon as one of the iterables runs out of items.
From your example code, it looks like you want to take the items for the different list from the longer string. To do that efficiently, figure out which string is the longer before you start looping.
I've renamed your strings because it's confusing to give strings a name starting with "list".
s1 = "ABCDEFABCDEF"
s2 = "AZBYCXDWEVFABCDEF"
identicals = []
different = []
small, large = (s1, s2) if len(s1) <= len(s2) else (s2, s1)
for x, y in zip(small, large):
if x == y:
identicals.append(y)
else:
different.append(y)
print(identicals)
print(different)
output
['A']
['Z', 'B', 'Y', 'C', 'X', 'D', 'W', 'E', 'V', 'F', 'A']
We can make the for loop more compact at the expense of readability. We put our destination lists into a tuple and then use the equality test to select which list in that tuple to append to. This works because False has a numeric value of 0, and True has a numeric value of 1.
for x, y in zip(small, large):
(different, identicals)[x == y].append(y)
The problem is the inner loop. You are comparing each of the letters in list1 with all the letters of list2.
Instead you should have a single loop:
identicals=[]
different=[]
short_list = list1 if len(list1)<= len(list2) else list2
for i in range(len(short_list):
if list1[i] == list2[i]:
identicals.append(list1[i])
else:
different.append(short_list[i])
Try this
a = "ABCDEFABCDEF"
b = "AZBYCXDWEVFABCDEF"
import numpy
A = numpy.array(list(a))
B = numpy.array(list(b))
common = A[:len(B)] [ (A[:len(B)] == B[:len(A)]) ]
different = A[:len(B)] [ - (A[:len(B)] == B[:len(A)]) ]
>>> list(common)
['A']
>>> list(different)
['B', 'C', 'D', 'E', 'F', 'A', 'B', 'C', 'D', 'E', 'F']

Comparing Order of 2 Python Lists

I am looking for some help comparing the order of 2 Python lists, list1 and list2, to detect when list2 is out of order.
list1 is static and contains the strings a,b,c,d,e,f,g,h,i,j. This is the "correct" order.
list2 contains the same strings, but the order and the number of strings may change. (e.g. a,b,f,d,e,g,c,h,i,j or a,b,c,d,e)
I am looking for an efficient way to detect when list2 is our of order by comparing it against list1.
For example, if list2 is a,c,d,e,g,i should return true (as the strings are in order)
While, if list2 is a,d,b,c,e should return false (as string d appears out of order)
First, let's define list1:
>>> list1='a,b,c,d,e,f,g,h,i,j'.split(',')
>>> list1
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
While your list1 happens to be in alphabetical order, we will not assume that. This code works regardless.
Now, let's create a list2 that is out-of-order:
>>> list2 = 'a,b,f,d,e,g,c,h,i,j'.split(',')
>>> list2
['a', 'b', 'f', 'd', 'e', 'g', 'c', 'h', 'i', 'j']
Here is how to test whether list2 is out of order or not:
>>> list2 == sorted(list2, key=lambda c: list1.index(c))
False
False means out-of-order.
Here is an example that is in order:
>>> list2 = 'a,b,d,e'.split(',')
>>> list2 == sorted(list2, key=lambda c: list1.index(c))
True
True means in-order.
Ignoring elements of list1 not in list2
Let's consider a list2 that has an element not in list1:
>>> list2 = 'a,b,d,d,e,z'.split(',')
To ignore the unwanted element, let's create list2b:
>>> list2b = [c for c in list2 if c in list1]
We can then test as before:
>>> list2b == sorted(list2b, key=lambda c: list1.index(c))
True
Alternative not using sorted
>>> list2b = ['a', 'b', 'd', 'd', 'e']
>>> indices = [list1.index(c) for c in list2b]
>>> all(c <= indices[i+1] for i, c in enumerate(indices[:-1]))
True
Why do you need to compare it to list1 since it seems like list1 is in alphabetical order? Can't you do the following?
def is_sorted(alist):
return alist == sorted(alist)
print is_sorted(['a','c','d','e','g','i'])
# True
print is_sorted(['a','d','b','c','e'])
# False
Here's a solution that runs in expected linear time. That isn't too important if list1 is always 10 elements and list2 isn't any longer, but with longer lists, solutions based on index will experience extreme slowdowns.
First, we preprocess list1 so we can quickly find the index of any element. (If we have multiple list2s, we can do this once and then use the preprocessed output to quickly determine whether multiple list2s are sorted):
list1_indices = {item: i for i, item in enumerate(list1)}
Then, we check whether each element of list2 has a lower index in list1 than the next element of list2:
is_sorted = all(list1_indices[x] < list1_indices[y] for x, y in zip(list2, list2[1:]))
We can do better with itertools.izip and itertools.islice to avoid materializing the whole zip list, letting us save a substantial amount of work if we detect that list2 is out of order early in the list:
# On Python 3, we can just use zip. islice is still needed, though.
from itertools import izip, islice
is_sorted = all(list1_indices[x] < list1_indices[y]
for x, y in izip(list2, islice(list2, 1, None)))
is_sorted = not any(list1.index(list2[i]) > list1.index(list2[i+1]) for i in range(len(list2)-1))
The function any returns true if any of the items in an iterable are true. I combined this with a generator expression that loops through all the values of list2 and makes sure they're in order according to list1.
if list2 == sorted(list2,key=lambda element:list1.index(element)):
print('sorted')
Let's assume that when you are writing that list1 is strings a,b,c,d,e,f,g,h,i that this means that a could be 'zebra' and string b could actually be 'elephant' so the order may not be alphabetical. Also, this approach will return false if an item is in list2 but not in list1.
good_list2 = ['a','c','d','e','g','i']
bad_list2 = ['a','d','b','c','e']
def verify(somelist):
list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
while len(list1) > 0:
try:
list1 = list1[:list1.index(somelist.pop())]
except ValueError:
return False
return True

Python: if element in one list, change element in other?

I have two lists (of different lengths). One changes throughout the program (list1), the other (longer) doesn't (list2). Basically I have a function that is supposed to compare the elements in both lists, and if an element in list1 is in list2, that element in a copy of list2 is changed to 'A', and all other elements in the copy are changed to 'B'. I can get it to work when there is only one element in list1. But for some reason if the list is longer, all the elements in list2 turn to B....
def newList(list1,list2):
newList= list2[:]
for i in range(len(list2)):
for element in list1:
if element==newList[i]:
newList[i]='A'
else:
newList[i]='B'
return newList
Try this:
newlist = ['A' if x in list1 else 'B' for x in list2]
Works for the following example, I hope I understood you correctly? If a value in B exists in A, insert 'A' otherwise insert 'B' into a new list?
>>> a = [1,2,3,4,5]
>>> b = [1,3,4,6]
>>> ['A' if x in a else 'B' for x in b]
['A', 'A', 'A', 'B']
It could be because instead of
newList: list2[:]
you should have
newList = list2[:]
Personally, I prefer the following syntax, which I find to be more explicit:
import copy
newList = copy.copy(list2) # or copy.deepcopy
Now, I'd imagine part of the problem here is also that you use the same name, newList, for both your function and a local variable. That's not so good.
def newList(changing_list, static_list):
temporary_list = static_list[:]
for index, content in enumerate(temporary_list):
if content in changing_list:
temporary_list[index] = 'A'
else:
temporary_list[index] = 'B'
return temporary_list
Note here that you have not made it clear what to do when there are multiple entries in list1 and list2 that match. My code marks all of the matching ones 'A'. Example:
>>> a = [1, 2, 3]
>>> b = [3,4,7,2,6,8,9,1]
>>> newList(a,b)
['A', 'B', 'B', 'A', 'B', 'B', 'B', 'A']
I think this is what you want to do and can put newLis = list2[:] instead of the below but prefer to use list in these cases:
def newList1(list1,list2):
newLis = list(list2)
for i in range(len(list2)):
if newLis[i] in list1:
newLis[i]='A'
else: newLis[i]='B'
return newLis
The answer when passed
newList1(range(5),range(10))
is:
['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B']

Combining elements in list using python

Given input:
list = [['a']['a', 'c']['d']]
Expected Ouput:
mylist = a,c,d
Tried various possible ways, but the error recieved is TypeError: list indices must be integers not tuple.
Tried:
1.
k= []
list = [['a']['a', 'c']['d']]
#k=str(list)
for item in list:
k+=item
print k
2.
print zip(*list)
etc.
Also to strip the opening and closing parenthesis.
What you want is flattening a list.
>>> import itertools
>>> l
[['a'], ['a', 'c'], ['d']]
>>> res = list(itertools.chain.from_iterable(l))
>>> res
['a', 'a', 'c', 'd']
>>> set(res) #for uniqify, but doesn't preserve order
{'a', 'c', 'd'}
Edit: And your problem is, when defining a list, you should seperate values with a comma. So, not:
list = [['a']['a', 'c']['d']]
Use commas:
list = [['a'], ['a', 'c'], ['d']]
And also, using list as a variable is a bad idea, it conflicts with builtin list type.
And, if you want to use a for loop:
l = [['a'], ['a', 'c'], ['d']]
k = []
for sublist in l:
for item in sublist:
if item not in k: #if you want list to be unique.
k.append(item)
But using itertools.chain is better idea and more pythonic I think.
While utdemir's answer does the job efficiently, I think you should read this - start from "11.6. Recursion".
The first examples deals with a similar problem, so you'll see how to deal with these kinds of problems using the basic tools.

Categories

Resources