如何旋转列表中的非连续元素

时间:2010-08-28 00:49:20

标签: java

我有一个List,其中包含根据索引访问的元素。在这个列表中,我需要能够根据它们的索引“旋转”4个元素的组。例如,在列表中

[a, b, c, d, e ,f , g, h, i, j, k, l]

我想旋转c,f,i,l以获得

[a, b, l, d, e ,c , g, h, f, j, k, i]

你将如何实现这个?

2 个答案:

答案 0 :(得分:6)

一个简单的解决方案

如果您只需要在List的4个索引处旋转1个元素,您就可以编写一个简单的通用方法,如下所示:

static <T> void rotate4(List<T> list, int i0, int i1, int i2, int i3) {
    T item = list.get(i3);
    item = list.set(i0, item);
    item = list.set(i1, item);
    item = list.set(i2, item);
    item = list.set(i3, item);
}

这会循环旋转任意List<T>的4个元素。请记住List.set返回之前在该索引处的元素,因此如果您愿意,可以以单行编写整个方法:

    // one-liner version
    list.set(i3, list.set(i2, list.set(i1, list.set(i0, list.get(i3)))));

使用此辅助方法,您将拥有:

    List<Character> list = Arrays.asList(
        'a','b','c','d','e','f','g','h','i','j','k','l'
    );

    System.out.println(list);
    // [a, b, c, d, e, f, g, h, i, j, k, l]
    //        *        *        *        *

    rotate4(list, 2, 5, 8, 11);

    System.out.println(list);       
    // [a, b, l, d, e, c, g, h, f, j, k, i]
    //        *        *        *        *

更通用的解决方案

IF 你需要一种方法来旋转任意数量的元素任意距离,然后你可以创建另一个List实时视图,并且然后你可以Collections.rotate查看。

IF 元素是连续的,例如,您只需使用subList

    List<Character> list = Arrays.asList(
        'a','b','c','d','e','f','g','h','i','j','k','l'
    );

    System.out.println(list);
    // [a, b, c, d, e, f, g, h, i, j, k, l]
    //     *  *  *  *  *

    System.out.println(list.subList(1, 6));
    // [b, c, d, e, f]

    Collections.rotate(list.subList(1, 6), -2);
    System.out.println(list);
    // [a, d, e, f, b, c, g, h, i, j, k, l]
    //     *  *  *  *  *

由于元素不是连续的,因此您无法使用subList,但您可以编写例如PeriodicalLiveViewList课程。你希望能够写出这样的东西:

    System.out.println(PeriodicalLiveViewList.of(list, 3, 2));
    // [c, f, i, l]

    Collections.rotate(PeriodicalLiveViewList.of(list, 3, 2), 1);

基本上你创建另一个List,其元素是另一个List的第3个元素,从索引2开始,作为实时视图

如果您使用的是番石榴,可以使用ForwardingList构建。如有必要,您也可以从头开始实现decorator pattern

相关问题

答案 1 :(得分:2)

这就是我想出的。这是一个相当简单的蛮力解决方案,但它是可扩展的。

import java.util.Arrays;
import java.util.List;

public class ArrayRotator {

    public static void main(String... args) {
        List<String> target = Arrays.asList("a", "b", "c", "d", "e", "f", "g",
                "h", "i", "j", "k", "l");
        System.out.println(target);
        target = rotate(target, 3);
        System.out.println(target);
    }

    private static List<String> rotate(List<String> aList, int anOffset) {
        String[] result = new String[aList.size()];
        for (int i = 0; i < aList.size(); i++) {
            if (0 == (i + 1) % anOffset) {
                if (aList.size() > (i + anOffset)) {
                    result[i + anOffset ] = aList.get(i);
                } else {
                    result[anOffset - 1] = aList.get(i);
                }
            } else {
                result[i] = aList.get(i);
            }
        }
        return Arrays.asList(result);
    }
}

这是我得到的输出:

[a, b, c, d, e, f, g, h, i, j, k, l]
[a, b, l, d, e, c, g, h, f, j, k, i]

在这种情况下,我没有考虑Collections功能,因为它似乎比这更复杂。我不确定哪种算法在大型列表上更有效。也许您可以将功能组合如下:

import java.util.List;

public class ListRotator {

    public static void main(String... args) {
        List<String> target = Arrays.asList("a", "b", "c", "d", "e", "f", "g",
                "h", "i", "j", "k", "l");
        System.out.println(target);
        rotate(target, 3);
        System.out.println(target);
    }

    private static void rotate(List<String> aList, int anOffset) {
        for (int i = anOffset-1; i < aList.size()-anOffset; i += anOffset) {
            Collections.rotate(aList.subList(i, i+anOffset), -1);
        }
        Collections.rotate(aList.subList(anOffset-1, aList.size()), 1);
    }

}

它生成与上面相同的输出。