Is there a concept of range in Haskell or other functional programming languages? Suppose I want to compute I_AMAX from BLAS (to find the smallest index of the largest element in vector x). A naive method would be something like
idamax x idx = foldr(imax) 0 (zip x idx)
where idx is the index vector and imax returns the tuple with the smallest index and largest value.
For example, some vector (say, [1, 7, 3, 5]), zipped with its index vector ([0, 1, 2, 3], which makes [(1, 0), (7, 1), (3, 2), (5, 2)]), then reduced with the maximum function (so (7, 1), or 7).
But the index knowledge should be implicit, since in a loop the index is self-evident. Is there a way to write this in Haskell?
tl;dr, what's the best way to write I_AMAX in Haskell?
Here's a version:
idamax :: Ord a => [a] -> Int
idamax = negate . snd . maximum . flip zip [0, -1..]
Explanation
First note that zipping to lists yields a list with length of the shortest input list. So we can use [0..] to attach natural indices to list elements:
zip [0..] [1, 7, 3, 5] = [(0, 1), (1, 7), (2, 3), (3, 5)]
So what we do is:
attach an (negated) index to each element in a list
find a pair with max value and least index (which is max here because of previous negation)
extract index from resulting pair
negate it back
For example, starting with [1, 4, 2, 4]:
attach index: [(1, 0), (4, -1), (2, -2), (4, -3)]
find maximum: (4, -1) (note that (4, -1) > (4, -3))
extract index: -1
negate: 1
Examples
>>> idamax [1..10]
9
>>> idamax [1, 3, 4, 2, 4]
2
>>> idamax "oh hello"
0
Related
I have 2 list where each list is of size 250000. I wanted to iterate thru the lists and return the values that are greater than 3.
For example:
import itertools
from array import array
import numpy as np
input = (np.array([list([8,1]), list([2,3,4]), list([5,3])],dtype=object), np.array([1,0,0,0,1,1,1]))
X = input[0]
y = input[1]
res = [ u for s in X for u in zip(y,s) ]
res
I don't get the expected output.
Actual res : [(1, 8), (0, 1), (1, 2), (0, 3), (0, 4), (1, 5), (0, 3)]
Expected output 1 : [(8,1), (1,0), (2, 0), (3, 0), (4, 1), (5, 1), (3, 1)]
Expected output 2 : [(8,1), (4, 1), (5, 1))] ---> for greater than 3
I took references from stackoverflow. Tried itertools as well.
Using NumPy to store lists of non-uniform lengths creates a whole lot of issues, like the ones you are seeing. If it were an array integers, you could simply do
X[X > 3]
but since it is an array of lists, you have to jump through all sorts of hoops to get what you want, and basically lose all the advantages of using NumPy in the first place. You could just as well use lists of lists and skip NumPy altogether.
As an alternative I would recommend using Pandas or something else more suitable than NumPy:
import pandas as pd
df = pd.DataFrame({
'group': [0, 0, 1, 1, 1, 2, 2],
'data': [8, 1, 2, 3, 4, 5, 4],
'flag': [1, 0, 0, 0, 1, 1, 1],
})
df[df['data'] > 3]
# group data flag
# 0 0 8 1
# 4 1 4 1
# 5 2 5 1
# 6 2 4 1
Use filter
For example:
input = [1, 3, 2, 5, 6, 7, 8, 22]
# result contains even numbers of the list
result = filter(lambda x: x % 2 == 0, input)
This should give you result = [2, 6, 8, 22]
Not sureI quite understand exactly what you're trying to do... but filter is probably a good way.
Given a list of tuples, [(x, y, z), ....., (x_n, y_n,z_n)], x, y are nonnegative number and z is either 0 or 1, I want to sort the list based on the following three criteria-
if x_i != x_j, sort on ascendening order of x(tuple[0])
if x_i == x_j and z_i != z_j, sort on ascendening order of z(tuple[2])
if x_i == x_j and z_i == z_j and z_i == 0, sort on descending order of y(tuple[1])
if x_i == x_j and z_i == z_j and z_i == 1, sort on ascending order of y(tuple[1])
Input: [(1, 1, 0), (2, 1, 1), (1, 2, 0), (2, 2, 1), (1, 3, 0), (2, 3, 1)]
output:[(1, 3, 0), (1, 2, 0), (1, 1, 0), (2, 1, 1), (2, 2, 1), (2, 3, 1)]
Since Python 3 does not support custom comparator function for sort as I know for JAVA, I do not know how to incorporate the above three criteria in the sort method.
I can sort based on the two criteria (either 1,2 or 1,3) of the above-mentioned criterion. Adding the third criteria makes one of 2 or 3 invalid. I am adding my code here-
points.sort(key=lambda p: p[2])
points.sort(key=lambda p: p[1], reverse=True)
points.sort(key=lambda p: p[0])
OUTPUT: [(1, 3, 0), (1, 2, 0), (1, 1, 0), (2, 3, 1), (2, 2, 1), (2, 1, 1)] (criteria 3 not satisfied)
Can anybody suggest, what should be the value of key argument in this situation? Thanks
Just encoding your criteria...
points.sort(key=lambda p: (p[0], p[2], p[1] if p[2] else -p[1]))
If you have truly ridiculously complicated sorting rules, you can just write a comparator function, then use functools.cmp_to_key to make it into a valid key argument. So write your insane comparator function, add from functools import cmp_to_key to the top of your file, then do:
points.sort(key=cmp_to_key(my_insane_comparator))
and it will work as expected. All cmp_to_key really does is make a custom class with a custom __lt__ (less than operator) that performs the work of the comparator in the __lt__ on each comparison.
I have two same length lists like [[-3, -2, 1],[2,3,5],[1,2,3]...[7,8,9]] and [-1,1,1,...1]. I would like to combine them as: [(-3,-2,1,-1), (2,3,5,1), (1,2,3,1)...(7,8,9,1)] in Python.
Appreciate if any comment.
>>> a = [(-3, -2, 1),(2,3,5),(1,2,3), (7,8,9)]
>>> b = [-1,1,1, 1]
>>> [i+(j,) for i, j in zip(a, b)]
[(-3, -2, 1, -1), (2, 3, 5, 1), (1, 2, 3, 1), (7, 8, 9, 1)]
Suppose I have a data set like below that shows an undirected graph:
1 2
1 3
1 4
3 5
3 6
7 8
8 9
10 11
I have a python script like it:
for s in ActorGraph.degree():
print(s)
that is a dictionary consist of key and value that keys are node names and values are degree of nodes:
('9', 1)
('5', 1)
('11', 1)
('8', 2)
('6', 1)
('4', 1)
('10', 1)
('7', 1)
('2', 1)
('3', 3)
('1', 3)
In networkx documentation suggest to use values() for having nodes degree.
now I like to have just keys that are degree of nodes and I use this part of script but it does't work and say object has no attribute 'values':
for s in ActorGraph.degree():
print(s.values())
how can I do it?
You are using version 2.0 of networkx. Which changed from using a dict for G.degree() to using a dict-like (but not dict) DegreeView. See this guide.
To have the degrees in a list you can use a list-comprehension:
degrees = [val for (node, val) in G.degree()]
I'd like to add the following: if you're initializing the undirected graph with nx.Graph() and adding the edges afterwards, just beware that networkx doesn't guarrantee the order of nodes will be preserved -- this also applies to degree(). This means that if you use the list comprehension approach then try to access the degree by list index the indexes may not correspond to the right nodes. If you'd like them to correspond, you can instead do:
degrees = [val for (node, val) in sorted(G.degree(), key=lambda pair: pair[0])]
Here's a simple example to illustrate this:
>>> edges = [(0, 1), (0, 3), (0, 5), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (2, 5)]
>>> g = nx.Graph()
>>> g.add_edges_from(edges)
>>> print(g.degree())
[(0, 3), (1, 4), (3, 3), (5, 2), (2, 4), (4, 2)]
>>> print([val for (node, val) in g.degree()])
[3, 4, 3, 2, 4, 2]
>>> print([val for (node, val) in sorted(g.degree(), key=lambda pair: pair[0])])
[3, 4, 4, 3, 2, 2]
You can also use a dict comprehension to get an actual dictionary:
degrees = {node:val for (node, val) in G.degree()}
I am trying to solve frequent values using Segment Tree
This blog article uses a similar approach
I want to split a list into intervals as:
-1 -1 1 1 1 1 3 10 10 10 becomes (0, 2) (2, 6) (6, 7), (7, 10)
I have a code as:
g s = map (\x->(head x, length x)) . group . sort $ s
But it does not give the correct output.
Is it possible with frequent values too?
I'd do it as
f = neighbors . prefixSums . counts
where
counts = map length . group . sort
prefixSums = scanl (+) 0
neighbors xs = zip xs (tail xs)
This starts by computing the counts of elements, so your (arbitrary permutation of) [-1, -1, 1, 1, 1, 1, 3, 10, 10, 10] becomes [2, 4, 1, 3].
Then, prefixSums computes the sums of prefixes, and so we get [0, 2, 6, 7, 10] for our running example.
To get the end result, we simply take the consecutive neighbors of this list.