Related
I know how to find the 1st highest value but don't know the rest. Keep in mind i need to print the position of the 1st 2nd and 3rd highest value.Thank You and try to keep it simple as i have only been coding for 2 months. Also they can be joint ranks
def linearSearch(Fscore_list):
pos_list = []
target = (max(Fscore_list))
for i in range(len(Fscore_list)):
if Fscore_list[i] >= target:
pos_list.append(i)
return pos_list
This will create a list of the 3 largest items, and a list of the corresponding indices:
lst = [9,7,43,2,4,7,8,5,4]
values = []
values = zip(*sorted( [(x,i) for (i,x) in enumerate(f_test)],
reverse=True )[:3] )[0]
posns = []
posns = zip(*sorted( [(x,i) for (i,x) in enumerate(f_test)],
reverse=True )[:3] )[1]
Things are a bit more complicated if the same value can appear multiple times (this will show the highest position for a value):
lst = [9,7,43,2,4,7,8,5,4]
ranks = sorted( [(x,i) for (i,x) in enumerate(lst)], reverse=True
)
values = []
for x,i in ranks:
if x not in values:
values.append( x )
posns.append( i )
if len(values) == 3:
break
print zip( values, posns )
Use heapq.nlargest:
>>> import heapq
>>> [i
... for x, i
... in heapq.nlargest(
... 3,
... ((x, i) for i, x in enumerate((0,5,8,7,2,4,3,9,1))))]
[7, 2, 3]
Add all the values in the list to a set. This will ensure you have each value only once.
Sort the set.
Find the index of the top three values in the set in the original list.
Make sense?
Edit
thelist = [1, 45, 88, 1, 45, 88, 5, 2, 103, 103, 7, 8]
theset = frozenset(thelist)
theset = sorted(theset, reverse=True)
print('1st = ' + str(theset[0]) + ' at ' + str(thelist.index(theset[0])))
print('2nd = ' + str(theset[1]) + ' at ' + str(thelist.index(theset[1])))
print('3rd = ' + str(theset[2]) + ' at ' + str(thelist.index(theset[2])))
Edit
You still haven't told us how to handle 'joint winners' but looking at your responses to other answers I am guessing this might possibly be what you are trying to do, maybe? If this is not the output you want please give us an example of the output you are hoping to get.
thelist = [1, 45, 88, 1, 45, 88, 5, 2, 103, 103, 7, 8]
theset = frozenset(thelist)
theset = sorted(theset, reverse=True)
thedict = {}
for j in range(3):
positions = [i for i, x in enumerate(thelist) if x == theset[j]]
thedict[theset[j]] = positions
print('1st = ' + str(theset[0]) + ' at ' + str(thedict.get(theset[0])))
print('2nd = ' + str(theset[1]) + ' at ' + str(thedict.get(theset[1])))
print('3rd = ' + str(theset[2]) + ' at ' + str(thedict.get(theset[2])))
Output
1st = 103 at [8, 9]
2nd = 88 at [2, 5]
3rd = 45 at [1, 4]
BTW : What if all the values are the same (equal first) or for some other reason there is no third place? (or second place?). Do you need to protect against that? If you do then I'm sure you can work out appropriate safety shields to add to the code.
Jupyter image of the code working
This question was on my Udemy machine learning course way too soon. Scott Hunter helped me the most on this problem, but didn't get me to a pass on the site. Having to really think about the issue deeper on my own. Here is my solution, since couldn't find it anywhere else online--in terms that I understood everything that was going on*:
lst = [9,7,43,2,4,7,8,9,4]
ranks = sorted( [(x,i) for (i,x) in enumerate(lst)], reverse=True )
box = []
for x,i in ranks:
if i&x not in box:
box.append( x )
if len(box) == 3:
break
print(box)
So we have a list of numbers. To rank the numbers we sort the value with its position for every position that has a value when we enumerate/iterate the list. Then we put the highest values on top by reversing it. Now we need a box to put our information in to pull out of later, so we build that box []. Now for every value with a position put that in the box, if the value and position isn't already in the box--meaning if the value is already in the box, but the position isn't, still put in the box. And we only want three answers. Finally tell me what is in the variable called box.
*Many of these answers, on this post, will most likely work.
Input : [4, 5, 1, 2, 9]
N = 2
Output : [9, 5]
Input : [81, 52, 45, 10, 3, 2, 96]
N = 3
Output : [81, 96, 52]
# Python program to find N largest
# element from given list of integers
l = [1000,298,3579,100,200,-45,900]
n = 4
l.sort()
print(l[-n:])
Output:
[298, 900, 1000, 3579]
lst = [9,7,43,2,4,7,8,9,4]
temp1 = lst
print(temp1)
#First Highest value:
print(max(temp1))
temp1.remove(max(temp1))
#output: 43
# Second Highest value:
print(max(temp1))
temp1.remove(max(temp1))
#output: 9
# Third Highest Value:
print(max(temp1))
#output: 7
There's a complicated O(n) algorithm, but the simplest way is to sort it, which is O(n * log n), then take the top. The trickiest part here is to sort the data while keeping the indices information.
from operator import itemgetter
def find_top_n_indices(data, top=3):
indexed = enumerate(data) # create pairs [(0, v1), (1, v2)...]
sorted_data = sorted(indexed,
key=itemgetter(1), # sort pairs by value
reversed=True) # in reversed order
return [d[0] for d in sorted_data[:top]] # take first N indices
data = [5, 3, 6, 3, 7, 8, 2, 7, 9, 1]
print find_top_n_indices(data) # should be [8, 5, 4]
Similarly, it can be done with heapq.nlargest(), but still you need to pack the initial data into tuples and unpack afterwards.
To have a list filtered and returned in descending order with duplicates removed try using this function.
You can pass in how many descending values you want it to return as keyword argument.
Also a side note, if the keyword argument (ordered_nums_to_return) is greater than the length of the list, it will return the whole list in descending order. if you need it to raise an exception, you can add a check to the function. If no args is passed it will return the highest value, again you can change this behaviour if you need.
list_of_nums = [2, 4, 23, 7, 4, 1]
def find_highest_values(list_to_search, ordered_nums_to_return=None):
if ordered_nums_to_return:
return sorted(set(list_to_search), reverse=True)[0:ordered_nums_to_return]
return [sorted(list_to_search, reverse=True)[0]]
print find_highest_values(list_of_nums, ordered_nums_to_return=4)
If values can appear in your list repeatedly you can try this solution.
def search(Fscore_list, num=3):
l = Fscore_list
res = dict([(v, []) for v in sorted(set(l), reverse=True)[:num]])
for index, val in enumerate(l):
if val in res:
res[val].append(index)
return sorted(res.items(), key=lambda x: x[0], reverse=True)
First it find num=3 highest values and create dict with empty list for indexes for it. Next it goes over the list and for every of the highest values (val in res) save it's indexes. Then just return sorted list of tuples like [(highest_1, [indexes ...]), ..]. e.g.
>>> l = [9, 7, 43, 2, 4, 7, 43, 8, 5, 8, 4]
>>> print(search(l))
[(43, [2, 6]), (9, [0]), (8, [7, 9])]
To print the positions do something like:
>>> Fscore_list = [9, 7, 43, 2, 4, 7, 43, 8, 5, 8, 4, 43, 43, 43]
>>> result = search(Fscore_list)
>>> print("1st. %d on positions %s" % (result[0][0], result[0][1]))
1st. 43 on positions [2, 6, 11, 12, 13]
>>> print("2nd. %d on positions %s" % (result[1][0], result[1][1]))
2nd. 9 on positions [0]
>>> print("3rd. %d on positions %s" % (result[2][0], result[2][1]))
3rd. 8 on positions [7, 9]
In one line:
lst = [9,7,43,2,8,4]
index = [i[1] for i in sorted([(x,i) for (i,x) in enumerate(lst)])[-3:]]
print(index)
[2, 0, 1]
None is always considered smaller than any number.
>>> None<4
True
>>> None>4
False
Find the highest element, and its index.
Replace it by None. Find the new highest element, and its index. This would be the second highest in the original list. Replace it by None. Find the new highest element, which is actually the third one.
Optional: restore the found elements to the list.
This is O(number of highest elements * list size), so it scales poorly if your "three" grows, but right now it's O(3n).
This is my list: a = [1, 3, 4, 7, 8, 9, 12, 13, 14].
I want to get the number that is closest to 5, this is the solution:
b = min(a, key = lambda x: abs(x-5))
Please explain what is happening in the above line.
The code is using the min builtin function, but with a key parameter. Thus, it does not return the actual minimum element of the list, but the element for which that key function is minimal, i.e. it behaves more like "arg-min" than actually "min".
In the key function (defined as a lambda expression), abs is just the absolute difference, in this case between the parameter x (a number from the list) and 5.
That line is somewhat equivalent to, but much shorter and more readable than, this loop:
a = [1,3,4,7,8,9,12,13,14]
b = min_k = None
for x in a:
k = abs(x-5)
if min_k is None or k < min_k:
b, min_k = x, k
Explanation
min(iterable, key) returns the smallest item in the iterable with respect to the key. So it iterates over the iterable, each time evaluates the key(x) for an element x, and then returns the element for which key(x) was the smallest.
Since key=lambda x=abs(x-5), we thus evaluate the absolute difference between 5, so if x=3, then abs(x-5) is 2, etc. So this will result in the number that is the closest to 5.
Making this an O(log n) algorithm
Given the list is ordered, you can find this in logarithmic time with:
from bisect import bisect_left
def closest(ordered_list, x):
idx = bisect_left(ordered_list, x)
return min(ordered_list[max(idx-1,0):idx+1], key=lambda y: abs(y-x))
For example:
>>> closest(a, -1)
1
>>> closest(a, 0)
1
>>> closest(a, 1)
1
>>> closest(a, 2)
1
>>> closest(a, 3)
3
>>> closest(a, 4)
4
>>> closest(a, 5)
4
>>> closest(a, 6)
7
>>> closest(a, 11)
12
>>> closest(a, 15)
14
abs(x-5)
abs is absolute mathematics function which is equivalent to |x-5|.
example : abs(x-5) when x=6 is 1, and when x=4 is also 1.
lambda x: abs(x-5)
It can be written as
def func(x):
return abs(x-5)
which means for a = [1,3,4,7,8,9,12,13,14]
lambda x: abs(x-5)
will give
[4, 2, 1, 2, 3, 4, 7, 8, 9]
key = lambda x: abs(x-5)
Here the value returned by this lambda function is stored in key variable.
Thus
key = [4, 2, 1, 2, 3, 4, 7, 8, 9]
Lastly min(a, key)
The min function uses key as an iterable to calculate minimum value.
Using the position of minimum value obtained from key it displays the value from iterable a.
Thus for
key = [4(0), 2(1), 1(2), 2(3), 3(4), 4(5), 7(6), 8(7), 9(8)]
minimum value is 1 at position 2 and it displays value at 2 position from iterable a
[1(0), 3(1), 4(2), 7(3), 8(4), 9(5), 12(6), 13(7), 14(8)]
which is 4.
try this
import numpy as np
def return_closest(a, num):
m1 = a[np.searchsorted(a, num)]
m2 = a[np.searchsorted(a, num)-1]
return m2 if abs(num-m1)>abs(num-m2) else m1
a = [1, 3, 4, 7, 8, 9, 12, 13, 14]
return_closest(a, 5)
gives 4
the function np.searchsorted will give you index of the upper limit (7)
I want to reorder number members in a list (the list contains number only), and if string form of num1 + string form of num2 >= string form of num2 + string form of num1, then num1 should be ahead of num2 (I cannot compare numbers directly since a number may be very large, or the concatenated string format of a number could be very large and overflow). Here is an example,
num1 = 3
num2 = 30
since num1+num2 > num2+num1 #'330' > '303'
so, 3 should be ahead of 30
Another example, input is [3, 30, 34, 5, 9], and expected output is [9, 5, 34, 3, 30], and wondering how to write Python code elegantly? Could we write a customized cmp method for a Python list?
It seems this method not working? After sorted step, l is still the same as original value?
def cmp_values(v1, v2):
_v1 = int('{0}{1}'.format(v1, v2))
_v2 = int('{0}{1}'.format(v2, v1))
return cmp(_v2, _v1)
if __name__ == "__main__":
l = [3, 30, 34, 5, 9]
sorted(l, cmp=cmp_values)
print l
thanks in advance,
Lin
You can use a custom cmp method to sort the list:
def cmp_values(v1, v2):
_v1 = int('{0}{1}'.format(v1, v2))
_v2 = int('{0}{1}'.format(v2, v1))
return cmp(_v2, _v1)
and then use it to sort the list
In [5]: l = [3, 30, 34, 5, 9]
In [6]: sorted(l, cmp=cmp_values)
Out[6]: [9, 5, 34, 3, 30]
You do need to take care of the overflow issue though. In case the combination of v1, and v2 exceeds the int range.
Based on further comments from #LinMa
Using sorted wouldn't change the original list, so you need to assign the returned list to a new variable:
new_list = sorted(l, cmp=cmp_values)
Your question is very vague...
Next time, make sure to format your code properly using proper indentations (found by clicking Code below the 'Undo' arrow.
When it comes to sorting out a list, just use .sort() function, like so:
new_list = [3,6,1,2,4,5]
new_list.sort()
print(new_list)
This should return:
[1, 2, 3, 4, 5, 6]
This is the simplest explanation of how to sort it. Hope this helps a little.
Same idea as AKS. Longer code but maybe easy to follow steps.
list = [3, 30, 34, 5, 9, 8]
job_done = False
while(job_done == False):
job_done = True
for i in range(len(list) - 1):
as_is = int('{0}{1}'.format(list[i], list[i + 1]))
swaped = int('{0}{1}'.format(list[i + 1], list[i]))
if as_is < swaped:
tmp = list[i]
list[i] = list[i + 1]
list[i + 1] = tmp
job_done = False
print list
I would like to know if there is a built in function in python for the equivalent Haskell scanl, as reduce is the equivalent of foldl.
Something that does this:
Prelude> scanl (+) 0 [1 ..10]
[0,1,3,6,10,15,21,28,36,45,55]
The question is not about how to implement it, I already have 2 implementations, shown below (however, if you have a more elegant one please feel free to show it here).
First implementation:
# Inefficient, uses reduce multiple times
def scanl(f, base, l):
ls = [l[0:i] for i in range(1, len(l) + 1)]
return [base] + [reduce(f, x, base) for x in ls]
print scanl(operator.add, 0, range(1, 11))
Gives:
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
Second implementation:
# Efficient, using an accumulator
def scanl2(f, base, l):
res = [base]
acc = base
for x in l:
acc = f(acc, x)
res += [acc]
return res
print scanl2(operator.add, 0, range(1, 11))
Gives:
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
Thank you :)
You can use this, if its more elegant:
def scanl(f, base, l):
for x in l:
base = f(base, x)
yield base
Use it like:
import operator
list(scanl(operator.add, 0, range(1,11)))
Python 3.x has itertools.accumulate(iterable, func= operator.add). It is implemented as below. The implementation might give you ideas:
def accumulate(iterable, func=operator.add):
'Return running totals'
# accumulate([1,2,3,4,5]) --> 1 3 6 10 15
# accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
it = iter(iterable)
total = next(it)
yield total
for element in it:
total = func(total, element)
yield total
Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), which gives the possibility to name the result of an expression, we can use a list comprehension to replicate a scan left operation:
acc = 0
scanned = [acc := acc + x for x in [1, 2, 3, 4, 5]]
# scanned = [1, 3, 6, 10, 15]
Or in a generic way, given a list, a reducing function and an initialized accumulator:
items = [1, 2, 3, 4, 5]
f = lambda acc, x: acc + x
accumulator = 0
we can scan items from the left and reduce them with f:
scanned = [accumulator := f(accumulator, x) for x in items]
# scanned = [1, 3, 6, 10, 15]
I had a similar need. This version uses the python list comprehension
def scanl(data):
'''
returns list of successive reduced values from the list (see haskell foldl)
'''
return [0] + [sum(data[:(k+1)]) for (k,v) in enumerate(data)]
>>> scanl(range(1,11))
gives:
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
As usual, the Python ecosystem is also overflowing with solutions:
Toolz has an accumulate capable of taking a user-supplied function as an argument. I tested it with lambda expressions.
https://github.com/pytoolz/toolz/blob/master/toolz/itertoolz.py
https://pypi.python.org/pypi/toolz
as does more_itertools
http://more-itertools.readthedocs.io/en/stable/api.html
I did not test the version from more-itertools, but it also can take a user-supplied function.
I have a list of lists and each list has a repeating sequence. I'm trying to count the length of repeated sequence of integers in the list:
list_a = [111,0,3,1,111,0,3,1,111,0,3,1]
list_b = [67,4,67,4,67,4,67,4,2,9,0]
list_c = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,23,18,10]
Which would return:
list_a count = 4 (for [111,0,3,1])
list_b count = 2 (for [67,4])
list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
Any advice or tips would be welcome. I'm trying to work it out with re.compile right now but, its not quite right.
Guess the sequence length by iterating through guesses between 2 and half the sequence length. If no pattern is discovered, return 1 by default.
def guess_seq_len(seq):
guess = 1
max_len = len(seq) / 2
for x in range(2, max_len):
if seq[0:x] == seq[x:2*x] :
return x
return guess
list_a = [111,0,3,1,111,0,3,1,111,0,3,1]
list_b = [67,4,67,4,67,4,67,4,2,9,0]
list_c = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,23,18,10]
print guess_seq_len(list_a)
print guess_seq_len(list_b)
print guess_seq_len(list_c)
print guess_seq_len(range(500)) # test of no repetition
This gives (as expected):
4
2
10
1
As requested, this alternative gives longest repeated sequence. Hence it will return 4 for list_b. The only change is guess = x instead of return x
def guess_seq_len(seq):
guess = 1
max_len = len(seq) / 2
for x in range(2, max_len):
if seq[0:x] == seq[x:2*x] :
guess = x
return guess
I took Maria's faster and more stackoverflow-compliant answer and made it find the largest sequence first:
def guess_seq_len(seq, verbose=False):
seq_len = 1
initial_item = seq[0]
butfirst_items = seq[1:]
if initial_item in butfirst_items:
first_match_idx = butfirst_items.index(initial_item)
if verbose:
print(f'"{initial_item}" was found at index 0 and index {first_match_idx}')
max_seq_len = min(len(seq) - first_match_idx, first_match_idx)
for seq_len in range(max_seq_len, 0, -1):
if seq[:seq_len] == seq[first_match_idx:first_match_idx+seq_len]:
if verbose:
print(f'A sequence length of {seq_len} was found at index {first_match_idx}')
break
return seq_len
This worked for me.
def repeated(L):
'''Reduce the input list to a list of all repeated integers in the list.'''
return [item for item in list(set(L)) if L.count(item) > 1]
def print_result(L, name):
'''Print the output for one list.'''
output = repeated(L)
print '%s count = %i (for %s)' % (name, len(output), output)
list_a = [111, 0, 3, 1, 111, 0, 3, 1, 111, 0, 3, 1]
list_b = [67, 4, 67, 4, 67, 4, 67, 4, 2, 9, 0]
list_c = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 0, 23, 18, 10
]
print_result(list_a, 'list_a')
print_result(list_b, 'list_b')
print_result(list_c, 'list_c')
Python's set() function will transform a list to a set, a datatype that can only contain one of any given value, much like a set in algebra. I converted the input list to a set, and then back to a list, reducing the list to only its unique values. I then tested the original list for each of these values to see if it contained that value more than once. I returned a list of all of the duplicates. The rest of the code is just for demonstration purposes, to show that it works.
Edit: Syntax highlighting didn't like the apostrophe in my docstring.