How to change pairs in a map?
For "faster" rotation the map could be replaced with a list and then method Collections.rotate
could be used for this purpose. Then the list elements may be accessed by index in range [0..25]
.
Or a small wrapper class may be implemented:
static class MyCharMap {
private List<Character> chars = IntStream
.rangeClosed('A', 'Z')
.mapToObj(c -> (char)c)
.collect(Collectors.toList());
public void rotate() {
Collections.rotate(chars, 1);
}
public Character get(Integer i) {
assert(1 <= i && i <= 26);
return chars.get(i - 1);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(4 * chars.size() + 2);
sb.append('{');
for (int i = 0, n = chars.size(); i < n; i++) {
if (i > 0) sb.append(", ");
sb.append(i + 1).append(':').append(chars.get(i));
}
sb.append('}');
return sb.toString();
}
}
Test:
MyCharMap chars = new MyCharMap();
chars.rotate();
chars.rotate();
System.out.println(chars);
System.out.println(chars.get(1));
Output:
{1:Y, 2:Z, 3:A, 4:B, 5:C, 6:D, 7:E, 8:F, 9:G, 10:H, 11:I, 12:J, 13:K, 14:L, 15:M, 16:N, 17:O, 18:P, 19:Q, 20:R, 21:S, 22:T, 23:U, 24:V, 25:W, 26:X}
Y
There is nothing wrong with your approach if using a map. But since rotations must be relative to some order and maps are unordered, you may want to use a List as suggested by Alex Rudenko.
Here is another alternative using maps. It permits left or right rotation by any amount (based on the sign) for a supplied map that has sequential integer keys starting at 1. It also adjusts for counts exceeding the size by using the remainder operator
. For left or right rotation offsets are simply calculated and the map altered and returned for subsequent processing.
BiFunction<Map<Integer, Character>, Integer, Map<Integer, Character>> rotate =
(mp, cnt) -> {
int size = mp.values().size();
int count = cnt < 0 ? size + (cnt % size) - 1 :
cnt - 1;
return mp.entrySet().stream()
.map(e -> new AbstractMap.SimpleEntry<>(
(e.getKey() + count) % size + 1,
e.getValue()))
.collect(Collectors.toMap(e -> e.getKey(),
e -> e.getValue()));
};
System.out.println(map); // original map - 10 elements
map = rotate.apply(map,1); // right one - starting at J
System.out.println(map);
map = rotate.apply(map,-2); // left two, skipping A, going to B
System.out.println(map);
map = rotate.apply(map, -21);// Essentially left one going to C
System.out.println(map);
map = rotate.apply(map, 22); // Essentially right two going to A
System.out.println(map);
prints
{1=A, 2=B, 3=C, 4=D, 5=E, 6=F, 7=G, 8=H, 9=I, 10=J}
{1=J, 2=A, 3=B, 4=C, 5=D, 6=E, 7=F, 8=G, 9=H, 10=I}
{1=B, 2=C, 3=D, 4=E, 5=F, 6=G, 7=H, 8=I, 9=J, 10=A}
{1=C, 2=D, 3=E, 4=F, 5=G, 6=H, 7=I, 8=J, 9=A, 10=B}
{1=A, 2=B, 3=C, 4=D, 5=E, 6=F, 7=G, 8=H, 9=I, 10=J}
The lambda version could easily be replaced by a regular method that takes a single rotate value and works on a fixed map.