【问题标题】:How rotate non consecutive elements in a list如何旋转列表中的非连续元素
【发布时间】:2010-08-28 00:49:19
【问题描述】:

我有一个列表,其中包含根据索引访问的元素。在这个列表中,我需要能够根据它们的索引“旋转”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]

你将如何实现这个?

【问题讨论】:

  • 直接实现有什么问题吗?就像找到每个元素的位置并替换它们一样。

标签: java


【解决方案1】:

一个简单的解决方案

如果您只需要在 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&lt;T&gt; 的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]
    //        *        *        *        *

更通用的解决方案

如果您需要一种方法将任意数量的元素旋转任意距离,然后您可以创建另一个List实时视图,然后您可以Collections.rotate那个观点。

如果元素是连续的,例如,你只需使用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,但你可以写e.g. PeriodicalLiveViewList 班级。你希望能够写出这样的东西:

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

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

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

如果您使用 Guava,您可以在 ForwardingList 上进行构建。如有必要,您也可以从头开始实现decorator pattern

相关问题

【讨论】:

  • 最干净的方式?然后比较两个数字的最干净的方法是对它们运行快速排序:) 说真的,这太不干净了,对于这个 5 行代码任务,我想不出更干净的解决方案。
  • 如果你对此给予赏金,我最多会在 2 天内写出这个 PeriodicalLiveViewList。 请说你在开玩笑,这里的整个 OOP 想法是个大笑话: )
  • @polygenelubricants 好吧,我必须说嵌套'set'调用的想法令人印象深刻! (虽然也不是很“干净”)无论如何,+1
  • 优秀的 OOP 风格的解决方案。 +1 @Nikita Java 是你最喜欢的语言吗?
  • @Nikita:subList 是一个非常强大和有用的机制。例如,文档规定了通过theList.subList(from, to).clear() 删除一系列元素的习惯用法。 PeriodicalLiveViewList 只是视图不是连续块而是周期性/周期性(即每个第 N 个元素)的变体。正如我之前提到的,我实际上有很多这样的视图用例。您是对的,对于这个特定问题,它可能是一个过度设计的解决方案,但如果提供,这对于许多列表操作场景来说是一个非常有价值的工具。
【解决方案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);
    }

}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-01
    • 2021-03-29
    • 1970-01-01
    • 2020-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多