Related
Given a list and a number, create a new list that contains each number of list at most N times, without reordering.
For example if the input number is 2, and the input list is [1,2,3,1,2,1,2,3], you take [1,2,3,1,2], drop the next [1,2] since this would lead to 1 and 2 being in the result 3 times, and then take 3, which leads to [1,2,3,1,2,3].
With list [20,37,20,21] and number 1, the result would be [20,37,21]
For example i had this like my attempt
from collections import Counter
def delete_nth(order, max_e):
c = Counter(order)
result = []
for key, value in c.items():
if value > max_e:
value = value - 1
return [x for x in c.items()]
and output is
dict_items([(20, 2), (37, 1), (21, 1)])
dict_items([(20, 2), (37, 1), (21, 1)])
From list [20, 37, 20, 21], 1 you get: [(20, 2), (37, 1), (21, 1)] should equal [20, 37, 21]
Log
dict_items([(1, 2), (3, 2), (7, 1), (2, 4)])
dict_items([(1, 2), (3, 2), (7, 1), (2, 4)])
From list [1, 1, 3, 3, 7, 2, 2, 2, 2], 3 you get: [(1, 2), (3, 2), (7, 1), (2, 4)] should equal [1, 1, 3, 3, 7, 2, 2, 2]
Log
dict_items([(1, 5), (2, 4), (3, 4), (4, 1), (5, 1)])
dict_items([(1, 5), (2, 4), (3, 4), (4, 1), (5, 1)])
dict_items([(1, 5), (2, 4), (3, 4), (4, 1), (5, 1)])
dict_items([(1, 5), (2, 4), (3, 4), (4, 1), (5, 1)])
dict_items([(1, 5), (2, 4), (3, 4), (4, 1), (5, 1)])
dict_items([(1, 5), (2, 4), (3, 4), (4, 1), (5, 1)])
From list [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], 3 you get: [(1, 5), (2, 4), (3, 4), (4, 1), (5, 1)] should equal [1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5]
From list [1, 1, 1, 1, 1], 5 you get: [(1, 5)] should equal [1, 1, 1, 1, 1]
Test Passed
Random tests
Testing for delete_nth([21, 45, 29, 29, 29, 6, 24, 45, 45, 45, 29, 21, 29, 24, 6, 45, 21, 38, 45, 21, 24, 45, 24, 6, 6, 29, 45, 29, 6, 45, 21, 29], 4)
Log
dict_items([(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)])
dict_items([(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)])
dict_items([(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)])
dict_items([(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)])
dict_items([(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)])
dict_items([(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)])
dict_items([(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)])
dict_items([(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)])
It should work on random inputs too!: [(21, 5), (45, 9), (29, 8), (6, 5), (24, 4), (38, 1)] should equal [21, 45, 29, 29, 29, 6, 24, 45, 45, 45, 29, 21, 24, 6, 21, 38, 21, 24, 24, 6, 6]
Testing for delete_nth([18, 18, 18, 18, 6, 23, 18, 46, 18, 31, 18, 31, 23, 18, 18, 31], 7)
Log
dict_items([(18, 9), (6, 1), (23, 2), (46, 1), (31, 3)])
dict_items([(18, 9), (6, 1), (23, 2), (46, 1), (31, 3)])
It should work on random inputs too!: [(18, 9), (6, 1), (23, 2), (46, 1), (31, 3)] should equal [18, 18, 18, 18, 6, 23, 18, 46, 18, 31, 18, 31, 23, 31]
Doing value = value - 1 only decrements the local variable value inside the loop; it doesn't decrement the actual value inside the Counter.
I might try building the list inside the loop as you decrement the counter:
from collections import Counter
def delete_nth(order, max_e):
# Build counter with maximum count max_e.
counts = {
i: min(max_e, count)
for i, count in Counter(order).items()
}
# Build result by iterating over original list.
result = []
for i in order:
if not counts[i]:
continue
counts[i] -= 1
result.append(i)
return result
assert delete_nth([1,2,3,1,2,1,2,3], 2) == [1,2,3,1,2,3]
Perhaps something like this?
def keep_at_most_n(arr, n):
count = {}
output = []
for element in arr:
if count.get(element, 0) < n:
output.append(element)
count[element] = count.get(element, 0) + 1
return output
As the title illustrated, I want to generate 100 pairs of random integers, such as (1, 0), (1, 31), (5, 7), (3, 19) and so on. And the range of value is from 0 to 31. At the same time, I hope each pair appears only once within the 100 pairs, i.e., the value of each pair is different from others.
So How can I achieve it in Python?
Supplement:
To be precise, what I want is a 2D array, and its shape is (100,2). Each row is required to be unique.
You can use random.sample:
import random
pool = range(32)
random.sample(pool, 2)
# [7, 28]
random.sample(pool, 2)
# [15, 3]
import numpy as np
pool_ = [ (i,j) for i in range(32) for j in range(32) ]
# List of all pairs
pool = np.zeros( len(pool_), dtype = tuple ) # Create an np.array of tuples
pool[:] = pool_ # fill it with pool_
selected = np.random.choice( pool, replace = False, size =100 )
# select 100 random choices from the pool, without replacement
print( selected )
# [(0, 22) (4, 30) (2, 25) (4, 19) (6, 6) (17, 22) (18, 14) (12, 27) (30, 6)
# (22, 18) (13, 5) (23, 22) (27, 17) (17, 26) (26, 22) (7, 15) (15, 27)
# (4, 31) (15, 1) (28, 22) (25, 16) (25, 15) (7, 12) (7, 21) (26, 14)
# (9, 9) (8, 0) (26, 27) (14, 14) (22, 0) (4, 18) (12, 3) (25, 9) (22, 31)
# (11, 6) (23, 7) (18, 19) (19, 25) (23, 19) (25, 5) (5, 19) (3, 24)
# (30, 0) (18, 10) (20, 4) (24, 11) (13, 28) (10, 5) (6, 7) (11, 7)
# (25, 24) (23, 18) (15, 10) (14, 7) (11, 11) (9, 23) (13, 8) (3, 28)
# (28, 3) (21, 3) (24, 31) (29, 27) (24, 28) (17, 6) (30, 19) (25, 28)
# (12, 17) (13, 15) (3, 11) (14, 1) (12, 6) (17, 17) (23, 2) (24, 18)
# (25, 11) (3, 26) (6, 2) (0, 28) (5, 12) (4, 1) (23, 17) (29, 23) (22, 17)
# (24, 15) (2, 5) (28, 11) (19, 27) (9, 20) (1, 11) (30, 5) (30, 21)
# (30, 28) (18, 31) (5, 27) (30, 11) (16, 0) (24, 16) (12, 30) (25, 25)
# (16, 22)]
I haven't thoroughly tested it but with replace = False in random.choice each selection should be unique.
To return a 2D array
import numpy as np
pool_ = [ (i,j) for i in range(32) for j in range(32) ]
# List of all pairs
pool_ix = np.arange( len(pool_) ) # index by row
pool = np.array(pool_) # 2D pool
selected_ix = np.random.choice( pool_ix, replace = False, size =100 )
pool[selected_ix, : ] # Select all of each selected row.
# array([[12, 19],
# [ 6, 23],
# [ 2, 3],
# [ 5, 20],
# :::
# [20, 3],
# [24, 20],
# [ 1, 28]])
Let's say we have a set of N nodes that can be coupled, as in a complex network, and we don't care of the direction of the link (so the link between 1 and 2 is the same as 2 and 1).
I want to use a numpy one-dimensional array to represent the state of each link. The state takes values in {1,0}, where 1 means that the link exists. The array, let's call it "state", should be N*(N-1)/2 long, I suppose (auto-loops are excluded).
In such a context, how could I index properly all the links that start in node a, or the links that end in node b? If we call the array "states", I would to say that state[i] = state of a link that starts in node a, or that end in node j. Is there a way, possibly an efficient way, to do this? If we have N=10 nodes, the first 8 entries correspond to links starting from node 1 and ending in nodes 2,3,4,...,10, but I can't find a general way to express this. Thanks.
P.s.: I know that a 2D matrix may be more useful, but for my purposes I would like to solve the issue keeping the states in a 1D array.
The index for pair of nodes (a,b) can be computed using a variable base determined by the number of preceding elements for the smaller of the two node IDs. Adding the larger one to that base gives the proper index:
You can make a function to get the state index from a pair of node identifiers (zero based) like this:
def indexOf(a,b,N=10):
return indexOf(b,a,N) if a>b else N*a-a*(a+1)//2+b
produces indexes as requested:
for a in range(10):
print([indexOf(a,b) for b in range(10)])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 10, 11, 12, 13, 14, 15, 16, 17, 18]
[2, 11, 19, 20, 21, 22, 23, 24, 25, 26]
[3, 12, 20, 27, 28, 29, 30, 31, 32, 33]
[4, 13, 21, 28, 34, 35, 36, 37, 38, 39]
[5, 14, 22, 29, 35, 40, 41, 42, 43, 44]
[6, 15, 23, 30, 36, 41, 45, 46, 47, 48]
[7, 16, 24, 31, 37, 42, 46, 49, 50, 51]
[8, 17, 25, 32, 38, 43, 47, 50, 52, 53]
[9, 18, 26, 33, 39, 44, 48, 51, 53, 54]
allPairs = [ (a,b) for a in range(10) for b in range(a,10) ]
print( sorted(allPairs,key=lambda ab:indexOf(*ab) ) )
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (6, 6), (6, 7), (6, 8), (6, 9), (7, 7), (7, 8), (7, 9), (8, 8), (8, 9), (9, 9)]
Note that this allocates entries for node links to themselves
The drawback of that indexing model is that it requires that the number of nodes (N) be known in advance and supplied on every call.
A more generic approach would be to index the flat list differently based on a progression that does not require having a predetermined value for N. Every pair will always be at the same index no matter the total number of nodes:
def indexOf(a,b):
return indexOf(b,a) if a<b else a*(a+1)//2+b
it can be reversed (to get the node pair at a given index) like this:
def unindex(X):
b = int( ((8*X+1)**0.5-1)/2 )
a = X - b*(b+1)//2
return a,b
The indexes are not in the same order but the function doesn't need to know N:
for a in range(10):
print([indexOf(a,b) for b in range(10)])
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
[1, 2, 4, 7, 11, 16, 22, 29, 37, 46]
[3, 4, 5, 8, 12, 17, 23, 30, 38, 47]
[6, 7, 8, 9, 13, 18, 24, 31, 39, 48]
[10, 11, 12, 13, 14, 19, 25, 32, 40, 49]
[15, 16, 17, 18, 19, 20, 26, 33, 41, 50]
[21, 22, 23, 24, 25, 26, 27, 34, 42, 51]
[28, 29, 30, 31, 32, 33, 34, 35, 43, 52]
[36, 37, 38, 39, 40, 41, 42, 43, 44, 53]
[45, 46, 47, 48, 49, 50, 51, 52, 53, 54]
print( [unindex(x) for x in range(N*(N+1)//2) ])
[(0, 0), (0, 1), (1, 1), (0, 2), (1, 2), (2, 2), (0, 3), (1, 3), (2, 3), (3, 3), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4), (0, 5), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (0, 6), (1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (0, 7), (1, 7), (2, 7), (3, 7), (4, 7), (5, 7), (6, 7), (7, 7), (0, 8), (1, 8), (2, 8), (3, 8), (4, 8), (5, 8), (6, 8), (7, 8), (8, 8), (0, 9), (1, 9), (2, 9), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9), (9, 9)]
Using numpy, if you have an array of node pairs, you can get their corresponding state indexes by writing the function (2nd version) like this:
import numpy as np
def indexOf(ab):
a,b = np.max(ab,axis=-1),np.min(ab,axis=-1)
return a*(a+1)//2 + b
output:
N = 10
states = np.arange(N*(N+1)//2)%2 # some random node links
pairs = np.array( [[1,3],[2,4],[7,2]] ) # array of node pairs
connected= states[indexOf(pairs)] # indirection to states
print(states)
# [0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0]
print(indexOf(pairs))
# [ 7 12 30]
print(connected)
# [1 0 0]
if you use the first version of the function, you will need to pass the number of nodes on every call:
def indexOf(ab,N=10):
a,b = np.min(ab,axis=-1),np.max(ab,axis=-1)
return N*a-a*(a+1)//2+b
connected= states[indexOf(pairs,N=10)]
Given:
setA = [(1, 25), (2, 24), (3, 23), (4, 22), (5, 21), (6, 20),
(7, 19), (8, 18), (9, 17), (10, 16), (11, 15), (12, 14),
(13, 13),(14, 12), (15, 11), (16, 10), (17, 9), (18, 8),
(19, 7),(20, 6), (21, 5), (22, 4), (23, 3), (24, 2), (25, 1)]
setB = [(1, 19), (2, 18), (3, 17), (4, 16), (5, 15), (6, 14), (7, 13),
(8, 12), (9, 11), (10, 10), (11, 9), (12, 8), (13, 7), (14, 6),
(15, 5), (16, 4), (17, 3), (18, 2), (19, 1)]
How can I combine the two sets using the first element of each tuple in each set as a common key value. So for tuple at position 1 in each set it would be (1,25) and (1,19) respectively. Joined together would yield: (25,1,19)
(25,1,19)
(24,2,18)
(23,3,17)
...
(7,19,1)
(6,20,none)
...
(2,24,none)
(1,25,none)
Note: that order of output tuple must be maintained. Example:
(setA value, common value, setB value)
(setA value, common value, setB value)etc...
Note: Must use Python 2.7x standard libraries
I'm trying to do something like [(a,b,c) for (a,b),(b,c) in zip(setA,setB)] but I don't fully understand the proper syntax and logic.
Thank you.
Seems like what you want can be implemented as easily as a dictionary lookup on setB inside a list comprehension.
mapping = dict(setB)
out = [(b, a, mapping.get(a)) for a, b in setA]
print(out)
[(25, 1, 19),
(24, 2, 18),
(23, 3, 17),
(22, 4, 16),
(21, 5, 15),
(20, 6, 14),
(19, 7, 13),
(18, 8, 12),
(17, 9, 11),
(16, 10, 10),
(15, 11, 9),
(14, 12, 8),
(13, 13, 7),
(12, 14, 6),
(11, 15, 5),
(10, 16, 4),
(9, 17, 3),
(8, 18, 2),
(7, 19, 1),
(6, 20, None),
(5, 21, None),
(4, 22, None),
(3, 23, None),
(2, 24, None),
(1, 25, None)]
Since our lists have different size zip is not a solution.
One solution could be using zip_longest method from itertools package.
finalSet = [(b, a, c[1] if c is not None else c) for (a,b), c in zip_longest(*setA,*setB)]
Output
(25, 1, 19)
(24, 2, 18)
(23, 3, 17)
(22, 4, 16)
(21, 5, 15)
(20, 6, 14)
(19, 7, 13)
(18, 8, 12)
(17, 9, 11)
(16, 10, 10)
(15, 11, 9)
(14, 12, 8)
(13, 13, 7)
(12, 14, 6)
(11, 15, 5)
(10, 16, 4)
(9, 17, 3)
(8, 18, 2)
(7, 19, 1)
(6, 20, None)
(5, 21, None)
(4, 22, None)
(3, 23, None)
(2, 24, None)
(1, 25, None)
setA = [(1, 25), (2, 24), (3, 23), (4, 22), (5, 21), (6, 20),
(7, 19), (8, 18), (9, 17), (10, 16), (11, 15), (12, 14),
(13, 13),(14, 12), (15, 11), (16, 10), (17, 9), (18, 8),
(19, 7),(20, 6), (21, 5), (22, 4), (23, 3), (24, 2), (25, 1)]
setB = [(1, 19), (2, 18), (3, 17), (4, 16), (5, 15), (6, 14), (7, 13),
(8, 12), (9, 11), (10, 10), (11, 9), (12, 8), (13, 7), (14, 6),
(15, 5), (16, 4), (17, 3), (18, 2), (19, 1)]
la, lb = len(setA), len(setB)
temp=[[setA[i][1] if i<la else None, i+1, setB[i][1] if i<lb else None] for i in range(0,max(la,lb))]
[[25, 1, 19],
[24, 2, 18],
[23, 3, 17],
[22, 4, 16],
[21, 5, 15],
[20, 6, 14],
[19, 7, 13],
[18, 8, 12],
[17, 9, 11],
[16, 10, 10],
[15, 11, 9],
[14, 12, 8],
[13, 13, 7],
[12, 14, 6],
[11, 15, 5],
[10, 16, 4],
[9, 17, 3],
[8, 18, 2],
[7, 19, 1],
[6, 20, None],
[5, 21, None],
[4, 22, None],
[3, 23, None],
[2, 24, None],
[1, 25, None]]
If you want setC in the same format as setA and setB. I think this workaround will do.
Entering values directly as tuple is not possible as tuples are immutable and hence we append the new tuples as list and then convert it to a tuple.
`
setC = []
i=0
while setA[0][i][0]== setB[0][i][0] and (i < min(len(setA[0]), len(setB[0]))-1):
setC.append((setA[0][i][1],setA[0][i][0], setB[0][i][1]))
i+=1
setC = [tuple(setC)]
`
I need a algorithm for find the longest weighted path in a directed, acyclic graph networkx.MultiDiGraph(). My graph has weighted edges and many edges have a null value as the weighting. In networkx doc I have found nothing for solve this problem. My graph has the following structure:
>>> print graph.nodes()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 20, 21, 22, 25, 26, 'end']
>>> print graph.edges()
[(0, 'end'), (1, 0), (1, 10), (1, 5), (2, 1), (2, 11), (2, 6), (3, 2), (3, 12), (3, 7), (4, 8), (4, 3), (4, 13), (5, 'end'), (6, 5), (6, 15), (7, 16), (7, 6), (8, 17), (8, 7), (10, 'end'), (11, 10), (11, 20), (11, 15), (12, 16), (12, 11), (12, 21), (13, 17), (13, 12), (13, 22), (15, 'end'), (16, 25), (16, 15), (17, 16), (17, 26), (20, 'end'), (21, 25), (21, 20), (22, 26), (22, 21), (25, 'end'), (26, 25)]
>>> print graph.edge[7][16]
{1: {'weight': 100.0, 'time': 2}}
>>> print graph.edge[7][6]
{0: {'weight': 0, 'time': 2}}
I find this her, but I have problems with the implementation:
networkx: efficiently find absolute longest path in digraph this solution is without weightings.
How to find the longest path with Python NetworkX? This solution transformed the weightings into negativ values, but my graph has null values… and the nx.dijkstra_path() does not support negative values.
Have anyone an idea or a solution to a similar problem found?
Take the solution in the link 1 and change the line:
pairs = [[dist[v][0]+1,v] for v in G.pred[node]] # incoming pairs
To something like:
pairs = [[dist[v][0]+edge['weight'],v] for u, edge in G[v][node] for v in G.pred[node]] # incoming pairs