Positional comparison in multiple lists - python

Trying to create multiple lists that are dependent on the previous list.
So for example list 1 would read a specific file and return either a number or the boolean false based on a comparison.
The second list would then compare the number that appears in the same position as those in the previous list (if the value from the previous list was not false) and return the value or false based on the same comparison as the first list
I created a function that carries out these comparisons and creates a list
def generic_state_machine(file,obs_nums):
return file.ix[:,0][obs_nums] if file.ix[:,0][obs_nums] > 0.2 else False
Note: obs_nums looks at the position of the item in a list
I then created the lists that look at different files
session_to_leads = []
lead_to_opps = []
for i in range(1,len(a)):
session_to_leads.append(generic_state_machine(file=a,obs_nums=i))
lead_to_opps.append(generic_state_machine(file=b,obs_nums=i)) if session_to_leads != False else lead_to_opps.append(False)
Given
a = pd.DataFrame([0,0.9,0.6,0.7,0.8])
b = pd.DataFrame([0.7,0.51,0.3,0.7,0.2])
I managed to sort out the initial error I encountered, the only problem now is that list lead_to_opps is not dependent on session_to_leads so if there is a False value in position 1, lead_to_opps will not automatically return a False in the same position. So assuming that random.uniform(0,1) generates 0.5 all the time, this is my current outcome:
session_to_leads = [False,0.9,0.6,0.7,0.8]
lead_to_opps = [0.7,0.51,False,0.7,False]
whereas my desired outcome would be
session_to_leads = [False,0.9,0.6,0.7,0.8]
lead_to_opps = [False,0.51,False,0.7,False]

"During handling of the above exception, another exception occurred:"
This is not an error, this is basically "based on the previous error, this new error occurred.
Please post the error before this one, it will help a lot.
Also, I did not got what is [obs_nums]

It looks like
file.ix[:, 1][obs_nums]
Is the problem, assuming .ix behaves like .loc (it seems .ix is deprecated)
>>> help(pd.Dataframe.loc)
Allowed inputs are...
- A slice object with labels, e.g. 'a':'f'
warning:: Note that contrary to usual python slices,
**both** the start and the stop are included
It's a bit difficult to follow the indexing but do you need to slice at all? Would just:
file.loc[obs_nums]
return the number or Boolean you are looking for?

Related

Unexpected result of checking type of values in a list - with regards to Booleans

When I have a list containing different values, I tried to check the type of each value and got an unexpected output. It was the Booleans True and False which threw me off. Follows the code and the results.
trial_set = {1,2,3,4,None, True, False}
new_list = [type(x) for x in trial_set]
new_set = {type(x) for x in trial_set}
print(new_list)
print(new_set)
Strange Boolean Type Behaviour
Questions:
Why does the datatype appear first in the output though they are the last two elements in the list?
Why is there only one datatype in output when I have two Booleans in the list?
I understand that Bool datatype is a substring of integer datatype and return 0 or 1 and I tried to figure this out from that angle but came up empty. Please help clarify.
Thank you in advance.
The result is because of the way Python sets work as well as how Booleans work under the hood. Since True == 1 in python, only a single occurrence of 1 or True will appear, in this case 1.
Also, sets in python are unordered so when you iterate it with a comprehension to make a list, the order is not guaranteed to be as you typed it.

Sorting in two different ways. But getting the wrong Output

below given are the two different ways of checking if a list is sorted.
Method 1
for i in range(len(inord) - 2):
if (inord[i] >= inord[i + 1]):
return False
return True
Method 2
temp = sorted(inord)
return min([1 if i==j else 0 for i,j in zip(temp,inord)])
The two methods are the same, But the second method fails in some cases, How could that just happen?.
The above question was asked with reference to the question from HackerRank. Check the below link for the complete code:
https://www.hackerrank.com/challenges/is-binary-search-tree/forum/comments/522743
There are two issues here:
The range in your first line doesn't compare the last two elements. It should be -1 instead of -2.
The first code block returns False if two adjacent elements are the same. In the other method, sorting doesn't change the order of same elements, so it returns True in the end. Do you want to check for monotonically increasing or strictly monotonically increasing values?
Does this help?

The truth value of a series is ambiguous: use

I get an error stating
ValueError:The truth value of a series is ambiguous for the if
condition.
with the the following function:
for i , row in train_news.iterrows():
if train_news.iloc[:,0].isin(['mostly-true','half-true','true']):
train_news.iloc[:,0] = "true"
else :
train_news.iloc[:,0] = "false"
The problem is in your if statement -
if train_news.iloc[:,0].isin(['mostly-true','half-true','true'])
Think about what this does -
Let's say train_news.iloc[:,0] looks like this -
mostly-true
not-true
half-true
Now if you do train_news.iloc[:,0].isin(['mostly-true','half-true','true']), this will check iteratively whether each element is present in the list ['mostly-true','half-true','true']
So, this will yield another pandas.Series which looks like this -
True
False
True
The if statement in python, being the simpleton, expects one bool value and you are just confusing it by providing a bunch of boolean values. So, either you need to use .all() or .any() (those are the usual to-do things) at the end depending upon what you want

Python list - string formatting as list indices

Depending on a condition I need to get a value from one or another function. I'm trying to put it inside a simple If ... Else statement. I tried to use %s string formatting but it won't work. Below code, so it will become more clear what I try to do:
if condition:
item = my_list['%s']
else:
item = my_other_list['%s']
# now I do something with this value:
print item % 3
This way I tried to print 3rd value of one or other list if the condition was True of False. This returned an error about list indices being string. So I tried to put it inside int() what didn't help.
How should I do it? The problem is I get the value later than I declare what item is.
EDIT
I will add some more infos here:
I have a for loop, that goes through ~1000 elements and processes them. If the condition is True, it calls one function or another if false. Now, I don't want to check the same condition 1000 times, because I know it won't change during the time and would like to check it once and apply the method to all of the elements.
More code:
if self.dlg.comboBox_3.currentIndex == 0:
item = QCustomTableWidgetItem(str(round((sum(values['%s'])/len(values['%s'])),2)))
else:
item = QCustomTableWidgetItem(str(round(sum(values['%s'],2))))
for row in range(len(groups)):
group = QTableWidgetItem(str(groups[row]))
qTable.setItem(row,0,group)
qTable.setItem(row,1,item % row)
This is the actual code. Not the '%s' and '% row'. I used simplified before not to distract from the actual problem, but I think it's needed. I'm sorry if it wasn't a good decision.
You have a reasonably large misconception about how list slicing works. It will always happen at the time you call it, so inside your if loop itself Python will be trying to slice either of the lists by the literal string "%s", which can't possibly work.
There is no need to do this. You can just assign the list as the output from the if statement, and then slice that directly:
if condition:
list_to_slice = my_list
else:
list_to_slice = my_other_list
# now I do something with this value:
print list_to_slice[3]
Short answer:
'%s' is a string by definition, while a list index should be an integer by definition.
Use int(string) if you are sure the string can be an integer (if not, it will raise a ValueError)
A list is made up of multiple data values that are referenced by an indice.
So if i defined my list like so :
my_list = [apples, orange, peaches]
If I want to reference something in the list I do it like this
print(my_list[0])
The expected output for this line of code would be "apples".
To actually add something new to a list you need to use an inbuilt method of the list object, which looks something like this :
my_list.append("foo")
The new list would then look like this
[apples, orange, peaches, foo]
I hope this helps.
I'd suggest wrapping around a function like this:
def get_item(index, list1, list2)
if condition:
return list1[index]
else:
return list2[index]
print get_item(3)
Here is a compact way to do it:
source = my_list if condition else my_other_list
print(source[2])
This binds a variable source to either my_list or my_other_list depending on the condition. Then the 3rd element of the selected list is accessed using an integer index. This method has the advantage that source is still bound to the list should you need to access other elements in the list.
Another way, similar to yours, is to get the element directly:
index = 2
if condition:
item = my_list[index]
else:
item = my_other_list[index]
print(item)

Index error while iterating through list and pop()-ing elements [duplicate]

This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 6 years ago.
import os
os.chdir('G:\\f5_automation')
r = open('G:\\f5_automation\\uat.list.cmd.txt')
#print(r.read().replace('\n', ''))
t = r.read().split('\n')
for i in range(len(t)):
if ('inherited' or 'device-group' or 'partition' or 'template' or 'traffic-group') in t[i]:
t.pop(i)
print(i,t[i])
In the above code, I get an index error at line 9: 'if ('inherited' or 'device-group'...etc.
I really don't understand why. How can my index be out of range if it's the perfect length by using len(t) as my range?
The goal is to pop any indexes from my list that contain any of those substrings. Thank you for any assistance!
This happens because you are editing the list while looping through it,
you first get the length which is 10 for example, then you loop through the thing 10 times. but as soon as you've deleted one thing the list will only be 9 long.
A way around this is to create a new list of things you want to keep and use that one instead.
I've slightly edited your code and done something similar.
t = ['inherited', 'cookies', 'device-group']
interesing_things = []
for i in t:
if i not in ['inherited', 'device-group', 'partition', 'template', 'traffic-group']:
interesing_things.append(i)
print(i)
Let's say len(t) == 5.
We'll process i taking values [0,1,2,3,4]
After we process i = 0, we pop one value from t. len(t) == 4 now. This would mean error if we get to i = 4. However, we're still going to try to go up to 4 because our range is already inited to be up to 4.
Next (i = 1) step ensures an error on i = 3.
Next (i = 2) step ensures an error on i = 2, but that is already processed.
Next (i = 3) step yields an error.
Instead, you should do something like this:
while t:
element = t.pop()
print(element)
On a side note, you should replace that in check with sets:
qualities_we_need = {'inherited', 'device-group', 'partition'} # put all your qualities here
And then in loop:
if qualities_we_need & set(element):
print(element)
If you need indexes you could either use one more variable to keep track of index of value we're currently processing, or use enumerate()
As many people said in the comments, there are several problems with your code.
The or operator sees the values on its left and right as booleans and returns the first one that is True (from left to right). So your parenthesis evaluates to 'inherited' since any non-empty string is True. As a result, even if your for loop was working, you would be popping elements that are equal to 'inherited' only.
The for loop is not working though. That happens because the size of the list you are iterating over is changing as you loop through and you will get an index-out-of-range error if an element of the list is actually equal to 'inherited' and gets popped.
So, take a look at this:
import os
os.chdir('G:\\f5_automation')
r = open('G:\\f5_automation\\uat.list.cmd.txt')
print(r.read().replace('\n', ''))
t = r.read().split('\n')
t_dupl = t[:]
for i, items in enumerate(t_dupl):
if items in ['inherited', 'device-group', 'partition', 'template', 'traffic-group']:
print(i, items)
t.remove(items)
By duplicating the original list, we can use its items as a "pool" of items to pick from and modify the list we are actually interested in.
Finally, know that the pop() method returns the item it removes from the list and this is something you do not need in your example. remove() works just fine for you.
As a side note, you can probably replace your first 5 lines of code with this:
with open('G:\\f5_automation\\uat.list.cmd.txt', 'r') as r:
t = r.readlines()
the advantage of using the with statement is that it automatically handles the closing of the file by itself when the reading is done. Finally, instead of reading the whole file and splitting it on linebreaks, you can just use the built-in readlines() method which does exactly that.

Categories

Resources