Related
I'm working in python for this problem.
Given a list of values that can increase or decrease in size between iterations (it will be padded to always be even)
users = [1,2,3,4,5,6,7,8]
Create a new random set of pairings for the users (order does not matter)
pairs_2 = [[2,5],[4,6],[3,8],[1,7]]
and ensure that the pairing does not overlap with the previous n sets of pairs
pairs_1 = [[7,10],[3,5],[1,6],[2,8],[4,9]]
pairs_0 = [[2,4],[3,6],[1,5]]
My current implementation just involves generating a random set of pairs and then doing a set intersection against the previous n pairings to see if it is unique or not, this obviously does not scale well nor guarantee a solution in any reasonable time.
I've also tried to instead generate all possible combinations of pairs, and then find the difference between that and all previous pairings, but then there is the problem of selecting exactly users/2 pairs from the list that contains all users. It feels like the first half of this solution is good as it guarantees only new pairs, but then requires some additional logic to select the pairs.
import random
myList = [[1,2,3,4,5,6],[1,2,3,4,5,6,7,8,9,10],[1,2,3,4,5,6,7,8]]
oldList = []
for e in range(0,len(myList)):
oldList.append([])
for d in range(0,len(myList[e]),2):
while True:
f = False
a = random.choice(myList[e])
myList[e].remove(a)
#print(myList,e)
b = random.choice(myList[e])
myList[e].remove(b)
#print(myList,e)
for c in oldList:
if [a,b] in c:
myList[e].append(a)
myList[e].append(b)
#print("Runned")
f = True
if f:
f = False
continue
oldList[e].append([a,b])
break
print(oldList)
All the result will be in oldList , It depend on which one you put in first
On your example , you should put in
myList = [[1,2,3,4,5,6],[1,2,3,4,5,6,7,8,9,10],[1,2,3,4,5,6,7,8]]
And the result will be:
[[[6, 3], [5, 4], [2, 1]], [[5, 2], [10, 8], [3, 4], [1, 9], [7, 6]], [[6, 1], [8, 5], [7, 3], [4, 2]]]
And to get different pair out according to your example
pair_0 = oldList[0]
pair_1 = oldList[1]
pair_2 = oldList[2]
and the result will be
pair_0 = [[6, 3], [5, 4], [2, 1]]
pair_1 = [[5, 2], [10, 8], [3, 4], [1, 9], [7, 6]]
pair_2 = [[6, 1], [8, 5], [7, 3], [4, 2]]
I was doing a puzzle and where i had to add 2 lists having same length to a new list and sort the list by the second element of the list.
for x in range(n):
tmp.append([start[x],end[x]])
where start and end are lists containing equal elements and n is the length of start and end.
Now, idk why a difference / error occurs between the use of following code.
end.sort()
for x in range(n):
tmp.append([start[x],end[x]])
and
for x in range(n):
tmp.append([start[x],end[x]])
tmp.sort(key=lambda x:x[1])
EDIT:-
Input list
start=[1, 3, 0, 5, 8, 5]
end=[2, 4, 6, 7, 9, 9]
output by sorting first
[[1, 2], [3, 4], [0, 6], [5, 7], [8, 9], [5, 9]]
output by sorting later
[[1, 2], [3, 4], [0, 6], [5, 7], [8, 9], [5, 9]]
works fine for this list but doesn't work for a bigger array
(array contains 80 elements thats why not uploading here)
If you sort end first, you combine the original order of start with the sorted order of end.
If you combine the two lists first and then sort by the end element, the start elements will get reordered, too, as they "tag along" with their end partner. Consider
start = [1, 2, 3]
end = [3, 2, 1]
Now, sorting end and combining, you'll end up with:
start = [1, 2, 3]
end = [1, 2, 3]
# =>
tmp = [[1, 1], [2, 2], [3, 3]]
Combining first, however, produces:
tmp = [[1, 3], [2, 2], [3, 1]]
And sorting this by the second element, will shuffle the old start elements as well:
tmp.sort(key=lambda x:x[1])
# [[3, 1], [2, 2], [1, 3]]
Side note: Check out zip:
tmp = list(zip(start, end))
Given the following arrays (arr,indices) ,I need to sort the array with respect to (i[0])th index in ascending order if i[1] equals 0 and descending order if i[1] equals 1 ,where i refers to each element of the indices array.
Constraints
1<= len(indices) <=10
1<= len(arr) <=10^4
Example
arr=[[1,2,3],[3,2,1],[4,2,1],[6,4,3]]
indices=[[2,0],[0,1]]
required output
[[4,2,1],[3,2,1],[6,4,3],[1,2,3]]
Explanation
first arr gets sorted with respect to 2nd index as (indices[0][0]=2) in ascending order as (indices[0][1]=0)
[[3,2,1],[ 4,2,1],[1,2,3],[6,4,3]]
then it gets sorted with 0th index as (indices[1][0]=0) in descending order as (indices[1][1]=1)
[[4,2,1],[3,2,1],[6,4,3],[1,2,3]]
Note
arr,indices need to be taken as input , so it is not possible for me to write arr.sort(key=lambda x: (x[2],-x[0]))
My Approach
I have tried the following but it is not giving the correct output
arr.sort(key=lambda x:next(x[i[0]] if i[1]==0 else -x[i[0]] for i in indices))
My output
[[3,2,1],[4,2,1],[1,2,3],[6,4,3]]
Expected output
[[4,2,1],[3,2,1],[6,4,3],[1,2,3]]
This one requires a very complex key. It looks to me like you have many different layers of sorting, here, and earlier elements of indices take precedence over later elements, when sort order would be affected.
I think what the sorting key needs to do is return a tuple/iterable, where the first element to sort by is whatever the first element of indices says to do, and the second element to sort by (in case of a tie in the first) is whatever the second element of indices says to do, and so on.
In which case you'd want something like this (a nested comprehension inside the key lambda, to generate that tuple (or, list, in this case)):
arr=[[1,2,3],[3,2,1],[4,2,1],[6,4,3]]
indices=[[2,0],[0,1]]
out = sorted(arr, key=lambda a: [
(-1 if d else 1) * a[i]
for (i, d) in indices
])
# [[4, 2, 1], [3, 2, 1], [6, 4, 3], [1, 2, 3]]
For sorting numbers only, you can use a quick hack of "multiply by -1 to sort descending instead of ascending". Which I did here.
You could use the stability:
from operator import itemgetter
for i, r in reversed(indices):
arr.sort(key=itemgetter(i), reverse=r)
This doesn't use the negation trick, so it also works for data other than numbers.
Check this out:
>>> a
[[6, 4, 3], [4, 2, 1], [3, 2, 1], [1, 2, 3]]
>>> i
[[2, 0], [0, 1]]
>>> for j in enumerate(i):
... a.sort(key=lambda x:x[j[1][0]],reverse=False if j[1][1]==0 else True)
... print(a)
...
[[3, 2, 1], [4, 2, 1], [1, 2, 3], [6, 4, 3]]
[[6, 4, 3], [4, 2, 1], [3, 2, 1], [1, 2, 3]]
Is this what you want?
I think in your second example is small mistake. It should be
[[6, 4, 3], [4, 2, 1], [3, 2, 1], [1, 2, 3]]
rather than
[[4,2,1],[3,2,1],[6,4,3],[1,2,3]]
this is under
then it gets sorted with 0th index as (indices[1][0]=0) in descending order as (indices[1][1]=1)
I have a table containing:
table = [[5, 7],[4, 3],[3, 3],[2, 3],[1, 3]]
and the first values represented in each list, (5,4,3,2,1) can be said to be an ID of a person. the second values represented (7,3,3,3,3) would be a score. What I'm trying to do is to detect duplicates values in the second column which is in this case is the 3s in the list. Because the 4 lists has 3 as the second value, i now want to sort them based on the first value.
In the table, notice that [1,3] has one as the first value hence, it should replace [4,3] position in the table. [2,3] should replace [3,3] in return.
Expected output: [[5,7],[1,3],[2,3],[3,3],[4,3]]
I attempted:
def checkDuplicate(arr):
i = 0
while (i<len(arr)-1):
if arr[i][1] == arr[i+1][1] and arr[i][0] > arr[i+1][0]:
arr[i],arr[i+1] = arr[i+1],arr[i]
i+=1
return arr
checkDuplicate(table)
The code doesn't fulfil the output i wanted and i would appreciate some help on this matter.
You can use sorted with a key.
table = [[5, 7], [4, 3], [3, 3], [2, 3], [1, 3]]
# Sorts by second index in decreasing order and then by first index in increasing order
sorted_table = sorted(table, key=lambda x: (-x[1], x[0]))
# sorted_table: [[5, 7], [1, 3], [2, 3], [3, 3], [4, 3]]
You should sort the entire list by the second column, using the first to break ties. This has the advantage of correctly grouping the threes even when the seven is interpersed among them, e.g. something like
table = [[4, 3],[3, 3],[5, 7],[2, 3],[1, 3]]
In Python, you can do it with a one-liner:
result = sorted(table, key=lambda x: (-x[1], x[0]))
If you want an in-place sort, do
table.sort(key=lambda x: (-x[1], x[0]))
Another neat thing you can do in this situation is to rely on the stability of Python's sorting algorithm. The docs actually suggest doing multiple sorts in complex cases like this, in the reverse order of the keys. Using the functions from operator supposedly speeds up the code as well:
from opetator import itemgetter
result = sorted(table, key=itemgetter(0))
result.sort(key=itemgetter(1), reversed=True)
The first sort will arrange the IDs in the correct order. The second will sort by score, in descending order, leaving the IDs undisturbed for identical scores since the sort is stable.
If you want to leave the list items with non-duplicate second elements untouched, and the ability to deal with the cases where multiple second items can be duplicate, I think you'll need more than the built-in sort.
What my function achieves:
Say your list is: table = [[5, 7], [6, 1], [8, 9], [3, 1], [4, 3], [3, 3], [2, 3], [1, 3]]
It will not touch the items [5, 7] and [8, 9], but will sort the remaining items by swapping them based on their second elements. The result will be:
[[5, 7], [3, 1], [8, 9], [6, 1], [1, 3], [2, 3], [3, 3], [4, 3]]
Here is the code:
def secondItemSort(table):
# First get your second values
secondVals = [e[1] for e in table]
# The second values that are duplicate
dups = [k for k,v in Counter(secondVals).items() if v>1]
# The indices of those duplicate second values
indices = dict()
for d in dups:
for i, e in enumerate(table):
if e[1]==d:
indices.setdefault(d, []).append(i)
# Now do the sort by swapping the items intelligently
for dupVal, indexList in indices.items():
sortedItems = sorted([table[i] for i in indexList])
c = 0
for i in range(len(table)):
if table[i][1] == dupVal:
table[i] = sortedItems[c]
c += 1
# And return the intelligently sorted list
return table
Test
Let's test on a little bit more complicated table:
table = [[5, 7], [6, 1], [8, 9], [3, 1], [4, 3], [3, 9], [3, 3], [2, 2], [2, 3], [1, 3]]
Items that should stay in their places: [5, 7] and [2, 2].
Items that should be swapped:
[6, 1] and [3, 1].
[8, 9] and [3, 9]
[4, 3], [3, 3], [2, 3], [1, 3]
Drumroll...
In [127]: secondItemSort(table)
Out[127]:
[[5, 7],
[3, 1],
[3, 9],
[6, 1],
[1, 3],
[8, 9],
[2, 3],
[2, 2],
[3, 3],
[4, 3]]
Sorry if I get terminology wrong - I've only just started learning Python, and I'm receiving instruction from friends instead of being on an actual course.
I want to search a list containing lots of arrays containing multiple elements, and find arrays with some elements matching, but some different.
In less confusing terms e.g. I have a list of arrays that each contain 2 elements (I think this is called a 2D array?) so:
list = [[1, 2], [2, 2], [3, 5], [4, 1], [5, 2], ...]
In my specific example, the first elements in each sub array just ascend linearly, but the second elements are almost random. I want to find or sort the arrays only by the second number. I could just remove the first number from each array:
list = [2, 2, 5, 1, 2 ...]
And then use something like "if list[x] == 1" to find '1' etc.
(side note: I'm not sure how to find ALL the values if one value is repeated - I can't remember quite what I wrote but it would only ever find the first instance where the value matched, so e.g. it would detect the first '2' but not the second or third)
But I want to keep the first values in each array. My friend told me that you could use a dictionary with values and keys, which would work for my example, but I want to know what the more general method would be.
So in my example, I hoped that if I wrote this:
if list[[?, x]] == [?, 1]
Then it would find the array where the second value of the array was 1, (i.e. [4, 1] in my example) and not care about the first value. Obviously it didn't work because '?' isn't Python syntax as far as I'm aware, but hopefully you can see what I'm trying to do?
So for a more general case, if I had a list of 5 dimensional arrays and I wanted to find the second and fourth values of each array, I would write:
if list[[?, x, ?, y, ?]] == [?, a, ?, b, ?]
And it would match any array where the value of the second element was 'a', and the value of the fourth was 'b'.
e.g. [3, a, 4, b, 7], [20, a, 1, b, 9], ['cat', a, 'dog', b, 'fish'] etc. would all be possible results found by the command.
So I want to know if there's any similar way to my method of using a question mark (but that actually works) to denote that an element in an array can have any value.
To sort on the second element for a list containg lists (or tuples):
from operator import itemgetter
mylist = [[1, 2], [2, 2], [3, 5], [4, 1], [5, 2]]
sortedlist = sorted(mylist, key=itemgetter(1))
See the Python sorting howto.
Use sorted if you want to keep original list unaffected
lst = [[1, 2], [2, 2], [3, 5], [4, 1], [5, 2]]
In [103]: sorted(lst, key=lambda x: x[1])
Out[103]: [[4, 1], [1, 2], [2, 2], [5, 2], [3, 5]]
else use list.sort to sort current list and keep sorted list
In [106]: lst.sort(key=lambda x: x[1])
In [107]: lst
Out[107]: [[4, 1], [1, 2], [2, 2], [5, 2], [3, 5]]
or use operator.itemgetter
from operator import itemgetter
In [108]: sorted(lst, key=itemgetter(1))
Out[108]: [[4, 1], [1, 2], [2, 2], [5, 2], [3, 5]]
You could use a list comprehension to build a list of all the desired items:
In [16]: seq = [[1, 2], [2, 2], [3, 5], [4, 1], [5, 2]]
To find all items where the second element is 1:
In [17]: [pair for pair in seq if pair[1] == 1]
Out[17]: [[4, 1]]
This finds all items where the second element is 2:
In [18]: [pair for pair in seq if pair[1] == 2]
Out[18]: [[1, 2], [2, 2], [5, 2]]
Instead of
if list[[?, x, ?, y, ?]] == [?, a, ?, b, ?]
you could use
[item for item in seq if item[1] == 'a' and item[3] == 'b']
Note, however, that each time you use a list comprehension, Python has to loop
through all the elements of seq. If you are doing this search multiple times,
you might be better off building a dict:
import collections
seq = [[1, 2], [2, 2], [3, 5], [4, 1], [5, 2]]
dct = collections.defaultdict(list)
for item in seq:
key = item[1]
dct[key].append(item)
And then you could access the items like this:
In [22]: dct[1]
Out[22]: [[4, 1]]
In [23]: dct[2]
Out[23]: [[1, 2], [2, 2], [5, 2]]
The list comprehension
[pair for pair in seq if pair[1] == 1]
is roughly equivalent to
result = list()
for pair in seq:
if pair[1] == 1:
result.append(pair)
in the sense that result would then equal the list comprehension.
The list comprehension is just a syntactically prettier way to express the same
thing.
The list comprehension above has three parts:
[expression for-loop conditional]
The expression is pair, the for-loop is for pair in seq, and the conditional is if pair[1] == 1.
Most, but not all list comprehensions share this syntax. The full list comprehension grammar is given here.