How to return ordened array names? - python

I have an array I want to sort from low to high, but I want it to return the array names (G, F, H...) instead of just the numbers. How do I do this?
A=12.74087388
B=12.48817861
C=12.31249807
D=12.95688859
E=12.49693343
F=11.51090636
G=10.16505019
H=11.99872655
Array=np.array([A,B,C,D,E,F,G,H])
sort=np.sort(Array)

Use a dictionary:
d = dict(A=12.74087388,
B=12.48817861,
C=12.31249807,
D=12.95688859,
E=12.49693343,
F=11.51090636,
G=10.16505019,
H=11.99872655)
and sort by value:
>>> sorted(d, key=d.get)
['G', 'F', 'H', 'C', 'B', 'E', 'A', 'D']
or keep the numbers and sort by value:
from operator import itemgetter
print(sorted(d.items(), key=itemgetter(1)))
Output:
[('G', 10.16505019),
('F', 11.51090636),
('H', 11.99872655),
('C', 12.31249807),
('B', 12.48817861),
('E', 12.49693343),
('A', 12.74087388),
('D', 12.95688859)]

As #jonrsharpe pointed out, the variable name isn't a property of those values, so you'll have to attach it differently. I think the easiest way is to go about it like this:
my_array = [[12.74087388, 'A'], [12.48817861, 'B'], etc]
my_sorted_array = sorted(my_array)
my_sorted_named_array = [i[1] for i in my_sorted_array]

This is a dictionary-based solution, as suggested in the comments.
lst = [12.74087388, 12.48817861, 12.31249807, 12.95688859,
12.49693343, 11.51090636, 10.16505019, 11.99872655]
d = dict(zip(list('ABCDEFGH'), lst))
sorted_names = list(zip(*sorted(d.items(), key=lambda x: x[1])))[0]
# ('G', 'F', 'H', 'C', 'B', 'E', 'A', 'D')

I suppose you prefer a list of tuples instead of a dictionary in case you have duplicated letters.
data = [
('A', 12.74087388),
('B', 12.48817861),
('C', 12.31249807),
('D', 12.95688859),
('E', 12.49693343),
('F', 11.51090636),
('G', 10.16505019),
('H', 11.99872655)
]
dt = np.dtype([('letter', np.unicode_, 1), ('num', np.float64)])
arr = np.array(data, dtype=dt)
arr.sort(order='num')

Related

How can I rearrange a set of values into new pattern on python and print results

so I will do my best to explain what I'm looking for,
at the moment I have a 100 item list that I want to repetitively shuffle using a set pattern to first check if the pattern will eventually bring me back to where I began
and 2 to print the result of each loop to a text file.
so using a 3 item list as my example
[a,b,c]
and the shuffle pattern [3 1 2]
where the 3rd item becomes the first.
the first item becomes the second
and the second item becomes the 3rd
on a loop would generate the following patterns
[a,b,c]
[3,1,2]
[c,a,b]
[b,c,a]
[a,b,c]
but I have a list at the moment of 100 items that I need to find every single arrangement for a few different patterns I would like to test out.
does anyone know of a way to do this in python please.
You can define function and call this function multi times like below:
>>> def func(lst, ptr):
... return [lst[idx-1] for idx in ptr]
>>> lst = ['a','b','c']
>>> ptr = [3,1,2]
>>> for _ in range(5):
... lst = func(lst, ptr)
... print(lst)
['c', 'a', 'b']
['b', 'c', 'a']
['a', 'b', 'c']
['c', 'a', 'b']
['b', 'c', 'a']
You could use numpy advanced integer indexing if your list contains a numeric type:
import numpy as np
original_list=[1,2,3]
numpy_array = np.array(original_list)
pattern = [2,1,0]
print(numpy_array[pattern])
>>> array([3, 2, 1])
def rearrange(pattern : list,L:list):
new_list = []
for i in pattern :
new_list.append(L[i-1])
return new_list
print(rearrange([3,1,2],['a','b','c']))
output :
['c', 'a', 'b']
Itertools could be what you need.
import itertools
p = itertools.permutations(['a','b','c', 'd'])
list(p)
Output:
[('a', 'b', 'c', 'd'),
('a', 'b', 'd', 'c'),
('a', 'c', 'b', 'd'),
('a', 'c', 'd', 'b'),
('a', 'd', 'b', 'c'),
('a', 'd', 'c', 'b'),
('b', 'a', 'c', 'd'),
('b', 'a', 'd', 'c'),
('b', 'c', 'a', 'd'),
('b', 'c', 'd', 'a'),
('b', 'd', 'a', 'c'),
('b', 'd', 'c', 'a'),
('c', 'a', 'b', 'd'),
('c', 'a', 'd', 'b'),
('c', 'b', 'a', 'd'),
('c', 'b', 'd', 'a'),
('c', 'd', 'a', 'b'),
('c', 'd', 'b', 'a'),
('d', 'a', 'b', 'c'),
('d', 'a', 'c', 'b'),
('d', 'b', 'a', 'c'),
('d', 'b', 'c', 'a'),
('d', 'c', 'a', 'b'),
('d', 'c', 'b', 'a')]
​

Finding match from a list of tuples

I have a list of tuples as below.
x = [('b', 'c'),
('c',),
('a', 'c', 'b'),
('b', 'c', 'a', 'd'),
('b', 'c', 'a'),
('a', 'b'),
('a', 'b', 'c', 'd'),
('a', 'c', 'b', 'd'),
('b',),
('c', 'a'),
('a', 'b', 'c'),
('a',)]
I want to give input like ('a') then it should give output like,
[('a', 'c', 'b'), ('a', 'b'),('a', 'b', 'c', 'd'),('a', 'c', 'b', 'd'),('a', 'b', 'c')]
#everything starts with a. But not "a".
or for input of ('a','b') it should give an output of
[('a', 'b', 'c', 'd'),('a', 'b', 'c')]
#everything start with ('a','b') but not ('a','b') itself.
I tried to use but no success.
print(filter(lambda x: ("a","b") in x, x))
>>> <filter object at 0x00000214B3A545F8>
def f(lst, target):
return [t for t in lst if len(t) > len(target) and all(a == b for a, b in zip(t, target))]
so that:
f(x, ('a', 'b'))
returns:
[('a', 'b', 'c', 'd'), ('a', 'b', 'c')]
Tuples are matched lexicographically in python, meaning that there elements are compared pair by pair, regardless of their type.
You can extract the portion of each tuple of the same length as your prefix and compare with ==:
def find_prefixes(prefix, sequence):
n = len(prefix)
return[x for x in sequence if x[:n] == prefix and len(x) > n]
List comprehensions of this type are indeed equivalent to filter calls, so you can do
def find_prefixes(prefix, sequence):
n = len(prefix)
return list(filter(lambda x: x[:n] == prefix and len(x) > n, sequence))
Doing a linear search is not a very efficient way to solve this problem. The data structure known as a Trie is made specifically for finding prefixes. It arranges all your data into a single tree. Here is a popular Python implementation you can use with the appropriate attribution: https://stackoverflow.com/a/11016430/2988730
Firstly, use list(filter(...)) to convert a filter object to a list, but your filter doesn't do what you want - it checks membership, not subsequence. You can check subsequence by using a slice.
Then you just need to add a check that the match is longer than the subsequence.
Also, a filter of a lambda is better written as a comprehension.
for sub in ('a',), ('a', 'b'):
n = len(sub)
out = [t for t in x if t[:n] == sub and len(t) > n]
print(out)
Output:
[('a', 'c', 'b'), ('a', 'b'), ('a', 'b', 'c', 'd'), ('a', 'c', 'b', 'd'), ('a', 'b', 'c')]
[('a', 'b', 'c', 'd'), ('a', 'b', 'c')]
list(filter(lambda y: all([y[i] == z for i,z in enumerate(inp)]) if len(y)>=len(inp) else False, x))
for
inp = ('a', 'b')
output will be
[('a', 'b'), ('a', 'b', 'c', 'd'), ('a', 'b', 'c')]

Python - Calculate combinations of different values as a sum

Given a list of tuples as following:
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h')
]
I'd like to calculate different combinations of those values, but not as a cartesian product, rather as a sum on some custom rules. To clarify, if we calculate the cartesian product between those tuples, we will get 3*2*3 = 18 different combinations. But my desire is to get something like this:
combinations = [
('a', 'd', 'f'),
('a', 'e', 'g'),
('a', 'e', 'h'),
('b', 'd', 'f'),
('b', 'e', 'g'),
('b', 'e', 'h'),
('c', 'd', 'f'),
('c', 'e', 'g'),
('c', 'e', 'h')
]
So the resulting list contains 9 different combinations instead of 18.
Example with 4 tuples:
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h'),
('i', 'j', 'k', 'l')
]
The result would be
combinations = [
('a', 'd', 'f', 'i'),
('a', 'e', 'g', 'j'),
('a', 'e', 'h', 'k'),
('a', 'e', 'h', 'l'),
('b', 'd', 'f', 'i'),
('b', 'e', 'g', 'j'),
('b', 'e', 'h', 'k'),
('b', 'e', 'h', 'l'),
('c', 'd', 'f', 'i'),
('c', 'e', 'g', 'j'),
('c', 'e', 'h', 'k'),
('c', 'e', 'h', 'l'),
]
To Explain the logic for the outputs further:
In both inputs, the first tuple is behaving as it would in a cartesian product.
However, all the other tuples except the first are being iterated (or zipped) together. Additionally, if one of the tuples being iterated together "runs out of values" so to speak, we use the last value in the tuple instead.
What would be the efficient way to achieve this?
With the extra example provided, we can figure out how the logic will look. Essentially, the first row is being treated specially and used in the normal "cartesian product" sense.
However, the rest of the rows are being effectively extended to the largest length, and being zipped together. Coding that up, it can look something like follows:
from itertools import product
def extend_to_max_len(tup, length):
'''extends a tuple to a specified length by
filling the empty spaces with last element of given tuple
'''
fill_count = length - len(tup)
return (*tup, *[tup[-1]]*fill_count)
def non_cartesian_sum(values):
'''Expects a list of tuples.
gives the output according to the custom rules:
top: first row: to be used for cartesian product with zip of remaining rows
bottom: remaining rows: extended to longest length before zipping
'''
if len(values) < 2:
print("Check length of input provided")
return None
top = values[0]
bottom = values[1:]
max_len = max(len(row) for row in bottom)
bottom = [extend_to_max_len(row, max_len) for row in bottom]
out = [(first, *rest) for first, rest in product(top, zip(*bottom))]
return out
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h'),
('i', 'j', 'k', 'l')
]
out = non_cartesian_sum(values)
print(out)
Output:
[('a', 'd', 'f', 'i'),
('a', 'e', 'g', 'j'),
('a', 'e', 'h', 'k'),
('a', 'e', 'h', 'l'),
('b', 'd', 'f', 'i'),
('b', 'e', 'g', 'j'),
('b', 'e', 'h', 'k'),
('b', 'e', 'h', 'l'),
('c', 'd', 'f', 'i'),
('c', 'e', 'g', 'j'),
('c', 'e', 'h', 'k'),
('c', 'e', 'h', 'l')]
Note that you may want to add more input validation as required, before using this function for your use case.
This works for the data provided.
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h')
]
length_of_1 = len(values[1])
length_of_2 = len(values[2])
output = []
for item0 in values[0]:
for i in range(max(length_of_1, length_of_2)):
if i >= length_of_1:
item1 = values[1][-1]
else:
item1 = values[1][i]
if i >= length_of_2:
item2 = values[2][-1]
else:
item2 = values[2][i]
triple = (item0, item1, item2)
output.append(triple)
for tup in output:
print(tup)
Output:
('a', 'd', 'f')
('a', 'e', 'g')
('a', 'e', 'h')
('b', 'd', 'f')
('b', 'e', 'g')
('b', 'e', 'h')
('c', 'd', 'f')
('c', 'e', 'g')
('c', 'e', 'h')
Try this
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h')
]
combination = [(a,b,c) for a in values[0] for b in values[1] for c in values[2]]
print(combination)

How to index nested lists in Python?

I have a nested list as shown below:
A = [('a', 'b', 'c'),
('d', 'e', 'f'),
('g', 'h', 'i')]
and I am trying to print the first element of each list using the code:
A = [('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i')]
print A[:][0]
But I get the following output:
('a', 'b', 'c')
Required output:
('a', 'd', 'g')
How to get this output in Python?
A[:] just creates a copy of the whole list, after which you get element 0 of that copy.
You need to use a list comprehension here:
[tup[0] for tup in A]
to get a list, or use tuple() with a generator expression to get a tuple:
tuple(tup[0] for tup in A)
Demo:
>>> A = [('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i')]
>>> [tup[0] for tup in A]
['a', 'd', 'g']
>>> tuple(tup[0] for tup in A)
('a', 'd', 'g')
You can transpose a list of lists/tuples with zip(*list_of_lists) then select the items you want.
>>> a
[('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i')]
>>> b = zip(*a)
>>> b
[('a', 'd', 'g'), ('b', 'e', 'h'), ('c', 'f', 'i')]
>>> b[0]
('a', 'd', 'g')
>>>
>>> c = zip(*a)[0]
>>> c
('a', 'd', 'g')
>>>
You can also do it this way:
>>> A = [('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i')]
>>> map(lambda t:t[0], A)
['a', 'd', 'g']
>>> tuple(map(lambda t:t[0],A))
('a', 'd', 'g')
Python lists don't work very well as multi-dimensional arrays.
If you're willing to add an extra dependency(e.g. if you're going to do a lot of array manipulation), numpy allows you to use the almost the exact syntax you're looking for
import numpy as np
A = np.array([('a', 'b', 'c'),
('d', 'e', 'f'),
('g', 'h', 'i')])
This outputs the row as an np.array(which can be accessed like a list):
>>> A[:,0]
array(['a', 'd', 'g'])
To get the first row as a tuple:
>>> tuple(A[:,0])
('a', 'd', 'g')
You can also get the behavior you want using pandas as follows:
In [1]: import pandas as pd
In [2]: A = [('a', 'b', 'c'),
('d', 'e', 'f'),
('g', 'h', 'i')]
In [3]: df = pd.DataFrame(A)
In [4]: df[:][0]
Out[4]:
0 a
1 d
2 g
Name: 0, dtype: object
In [5]: df[:][0].values
Out[5]: array(['a', 'd', 'g'], dtype=object)

Python permutation as list comprehension

I've got a list of strings and a permutation. I'm trying to apply the permutation to the list, but I'm trying to keep my code clean and concise. At the moment I have a working solution, and it looks like this:
mylist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
permutation = [5,2,6,3,7,9,1,4,8]
mynewlist = ['']*9
for i in range(9):
mynewlist[permutation[i]-1] = mylist[i]
print mynewlist
What I don't like about it is that I have to initialize the list to an empty list first, and then loop through it in an odd manner. I was just wondering if someone could come up with a cleaner way to write this, perhaps using a list comprehension? Or by applying a map?
For reference purposes - the result of the above is:
['g', 'b', 'd', 'h', 'a', 'c', 'e', 'i', 'f']
Your algorithm, but cleaner:
mynewlist = mylist[:]
for pos, elem in zip(permutation, mylist):
mynewlist[pos - 1] = elem
You could use sorted():
sorted(mylist, key=lambda v, i=iter(permutation): next(i))
This outputs:
>>> sorted(mylist, key=lambda v, i=iter(permutation): next(i))
['g', 'b', 'd', 'h', 'a', 'c', 'e', 'i', 'f']
This sorts the input mylist according to the indices taken from the permutation list; the key function is called for each element in the input sequence in order, once, before sorting.
This does not compare that favorably with your version though; you have a O(n) algorithm, this takes O(n lg n).
Just a crazy thought, but how about...
>>> mylist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
>>> permutation = [5,2,6,3,7,9,1,4,8]
>>> {permutation[i]: v for i, v in enumerate(mylist)}.values()
['g', 'b', 'd', 'h', 'a', 'c', 'e', 'i', 'f']
...exploiting the fact that dictionaries are sorted by hash values, and integers hash to their own value.
I think this is an O(n) algorithm.
Here is my attempt:
mynewlist = [list_item for p, list_item in sorted(zip(permutation, mylist))]
The result is:
['g', 'b', 'd', 'h', 'a', 'c', 'e', 'i', 'f']
Discussion
Let's start from the right. The zip() function couples the two lists together:
>>> zip(permutation, mylist)
[(5, 'a'), (2, 'b'), (6, 'c'), (3, 'd'), (7, 'e'), (9, 'f'), (1, 'g'), (4, 'h'), (8, 'i')]
We can then sort the result of the zip() function, which will produce a list of tuples sorted by permutation index:
>>> sorted(zip(permutation, mylist))
[(1, 'g'), (2, 'b'), (3, 'd'), (4, 'h'), (5, 'a'), (6, 'c'), (7, 'e'), (8, 'i'), (9, 'f')]
This is almost what we want: the characters are in order. The next step is to eliminate the permutation index, leaving just the characters. That's the final form I presented above.

Categories