1 package com.github.davidmoten.rx.internal.operators;
2
3 import java.util.Iterator;
4 import java.util.List;
5
6 public final class Permutations {
7
8 private Permutations() {
9
10 }
11
12 public static <T> Iterable<Swap<T>> iterable(final List<T> list) {
13 return new Iterable<Swap<T>>() {
14 @Override
15 public Iterator<Swap<T>> iterator() {
16 return new PermutationsSwapIterator<T>(list);
17 }
18 };
19 }
20
21 public static <T> Iterator<Swap<T>> iterator(List<T> list) {
22 return new PermutationsSwapIterator<T>(list);
23 }
24
25 private static class PermutationsSwapIterator<T> implements Iterator<Swap<T>> {
26
27
28
29
30
31
32
33 private final T[] values;
34 private final DirectedReference[] references;
35
36 @SuppressWarnings("unchecked")
37 public PermutationsSwapIterator(List<T> list) {
38 this.values = (T[]) list.toArray();
39 this.references = new DirectedReference[list.size()];
40 for (int i = 0; i < this.references.length; i++) {
41 this.references[i] = new DirectedReference(-1, i);
42 }
43 }
44
45 private boolean isMobile(int index) {
46 if (index == 0 && references[index].direction == -1) {
47 return false;
48 } else if (index == references.length - 1 && references[index].direction == 1) {
49 return false;
50 } else if (references[index
51 + references[index].direction].reference > references[index].reference) {
52 return false;
53 } else {
54 return true;
55 }
56 }
57
58 @Override
59 public boolean hasNext() {
60 for (int i = 0; i < references.length; i++) {
61 if (isMobile(i)) {
62 return true;
63 }
64 }
65 return false;
66 }
67
68 @Override
69 public Swap<T> next() {
70
71 int chosen = Integer.MIN_VALUE;
72 int chosenIndex = -1;
73 for (int i = 0; i < references.length; i++) {
74 if (isMobile(i) && references[i].reference > chosen) {
75 chosen = references[i].reference;
76 chosenIndex = i;
77 }
78 }
79
80
81 int neighbourIndex = chosenIndex + references[chosenIndex].direction;
82 Swap<T> swap = new Swap<T>(values[references[chosenIndex].reference],
83 values[references[neighbourIndex].reference]);
84
85 DirectedReference tmp = references[chosenIndex];
86 references[chosenIndex] = references[neighbourIndex];
87 references[neighbourIndex] = tmp;
88
89
90 for (int i = 0; i < references.length; i++) {
91 if (references[i].reference > chosen) {
92 references[i].reverse();
93 }
94 }
95
96 return swap;
97 }
98
99 @Override
100 public void remove() {
101 throw new UnsupportedOperationException("cannot remove from permutations");
102 }
103
104 }
105
106 public static class Swap<T> {
107 private final T left;
108 private final T right;
109
110 Swap(T left, T right) {
111 this.left = left;
112 this.right = right;
113 }
114
115 public T left() {
116 return left;
117 }
118
119 public T right() {
120 return right;
121 }
122
123 @Override
124 public String toString() {
125 return "Swap [left=" + left + ", right=" + right + "]";
126 }
127
128 }
129
130 private static class DirectedReference {
131 private final int reference;
132 private int direction;
133
134 DirectedReference(int direction, int reference) {
135 this.direction = direction;
136 this.reference = reference;
137 }
138
139 public void reverse() {
140 this.direction = -this.direction;
141 }
142
143 @Override
144 public String toString() {
145 String val = String.valueOf(reference);
146 String result = direction == -1 ? "<" + val : val + ">";
147 return result + String.valueOf(reference);
148 }
149 }
150
151 }