-1

I am trying to implement an "i not equal to j" (i<j) loop, which skips cases where i = j, but I would further like to make the additional requirement that the loop does not repeat the permutation of (j,i), if (i,j) has already been done (since, due to symmetry, these two cases give the same solution).

First Attempt

In the code to follow, I make the i<j loop by iterating through the following lists, where the second list is just the first list rolled ahead 1:

mylist = ['a', 'b', 'c']
np.roll(mylist,2).tolist() = ['b', 'c', 'a']

The sequence generated by the code below turns out to not be what I want:

import numpy as np

mylist = ['a', 'b', 'c']
for i in mylist:
    for j in np.roll(mylist,2).tolist():
        print(i,j)

since it returns a duplicate a a and has repeated permutations a b and b a:

a b
a c
a a
b b
b c
b a
c b
c c
c a

The desired sequence should instead be the pair-wise combinations of the elements in mylist, since for N=3 elements, there should only be N*(N-1)/2 = 3 pairs to loop through:

a b
a c
b c
develarist
  • 1,224
  • 1
  • 13
  • 34
  • 1
    You could use numpy https://stackoverflow.com/questions/15792465/how-to-do-circular-shift-in-numpy – Thomas Sablik Jan 11 '21 at 10:54
  • `np.roll` would be good. any way to not repeat the permutation of j and i, if i and j has already been done? (since, due to symmetry, the j and i case contains the same answer as i and j) – develarist Jan 11 '21 at 11:00
  • Can you clarify just what exactly you are asking? Do you want to rotate the list (move all elements up and 1st to last)? Do you want to iterate on the list as if it were rotated? Do you actually need a ``list``, or are other sequence types such as ``deque`` also appropriate? – MisterMiyagi Jan 11 '21 at 11:06
  • 1
    The question shows the actual output. What is the *desired* output? Are you looking for [pairwise permutations](https://docs.python.org/3/library/itertools.html#itertools.permutations) perhaps? – MisterMiyagi Jan 11 '21 at 11:16
  • " an "i not equal to j" (i – develarist Jan 11 '21 at 11:19
  • 1
    please provide an ACTUAL expected output as a print or a list etc. in question. its not clear to me by what you are mentioning here. Its better to avoid subjectivity when you can. – Akshay Sehgal Jan 11 '21 at 11:20
  • see edit for desired output since i could not write code notation with line breaks in comments – develarist Jan 11 '21 at 11:22
  • So by the edit, i see that you simply want the permutations of the elements while ensuring the sequence of the elements is retained from the original sequence? – Akshay Sehgal Jan 11 '21 at 11:24
  • if a list has N elements, there should only be N*(N-1)/2 solutions to ensure i – develarist Jan 11 '21 at 11:25
  • So your goal is to get the [pairwise combinations](https://docs.python.org/3/library/itertools.html#itertools.combinations)? Do you actually need the intermediate step of rolling the list? – MisterMiyagi Jan 11 '21 at 11:26
  • yes i would like to know how to do this i – develarist Jan 11 '21 at 11:26
  • Check if my updated answer suits your requirement – Akshay Sehgal Jan 11 '21 at 11:30

2 Answers2

2

You can do this using quite a hacky method just by removing the first element and appending it:

mylist.append(mylist.pop(0))

Where .append(...) will append an element to the end of a list, and .pop(...) will remove an element from a given index and return it.

Diggy.
  • 6,744
  • 3
  • 19
  • 38
2

You can use list.insert to help with left shift and right shift.

list.pop, removes the element from the original list and returns it as well. list.insert adds the returned element into the list at given index (0 or -1 in this case). NOTE: this operation is in place!

#Left shift
mylist = ['apples', 'guitar', 'shirt']
mylist.insert(-1,mylist.pop(0))
mylist

### ['guitar', 'apples', 'shirt']
#Right shift
mylist = ['apples', 'guitar', 'shirt']
mylist.insert(0,mylist.pop(-1))
mylist

### ['shirt', 'apples', 'guitar']

A better way to do this is with collections.deque. This will allow you to work with multiple shifts and has some other neat queue functions available as well.

from collections import deque

mylist = ['apples', 'guitar', 'shirt']
q = deque(mylist)
q.rotate(1)       # Right shift ['shirt', 'apples', 'guitar']
q.rotate(-1)      # Left shift ['guitar', 'shirt', 'apples']
q.rotate(3)       #Right shift of 3 ['apples', 'guitar', 'shirt']

EDIT: Based on your comments, you are trying to get permutations -

from itertools import product
[i for i in product(l, repeat=2) if len(set(i))>1]
[('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]

OR

out = []
for i in l:
    for j in l:
        if len(set([i,j]))>1:
               print(i,j)
a b
a c
b a
b c
c a
c b
Akshay Sehgal
  • 18,741
  • 3
  • 21
  • 51
  • sorry, prefer not to use `itertools` or `deque`. just normal python – develarist Jan 11 '21 at 11:30
  • 2
    but you do use numpy – Akshay Sehgal Jan 11 '21 at 11:31
  • i use numpy but convert back to the list, if there is no way to roll the list *with* the list. and the point is not to only get back the iterables. this will be an actual loop containing functions inside. i only demonstrated what the desired sequence should be – develarist Jan 11 '21 at 11:31
  • See thats the part I am not sure about. for permutations you DONT need rolling. Just a cross product of elements. Itertools is the baseline library to work with iterators (used more often than numpy which has limited uses). – Akshay Sehgal Jan 11 '21 at 11:33
  • You still get a list as output. and the object jsut creates an iterator – Akshay Sehgal Jan 11 '21 at 11:33
  • let's do what `itertools` does without `itertools` – develarist Jan 11 '21 at 11:34
  • the latest edit there looks better, but it's returning 6 results when there should only be 3. and again, the point isnt to print the deesired iterations. we need to actually do the desired sequence and no extra, unnecessary iterations – develarist Jan 11 '21 at 12:51