简体   繁体   English

重复数组的元素

[英]Repeating the elements of an array

How can I repeat the elements of an array in Java? 如何在Java中重复数组的元素?

For example, given the array {a,b,c,d,e,f} and a number n , I want to produce an n -element array that looks like {a,b,c,d,e,f,a,b,c,d,e,f,a,b,c,...} . 例如,给定数组{a,b,c,d,e,f}和数字n ,我想生成一个看起来像{a,b,c,d,e,f,a,b,c,d,e,f,a,b,c,...}n元素数组{a,b,c,d,e,f,a,b,c,d,e,f,a,b,c,...}

If I knew the length of the input and output arrays in advance, I could just write something like this: 如果我事先知道输入和输出数组的长度,我可以写这样的东西:

int a=input[0], b=input[1], c=input[2], d=input[3], e=input[4], f=input[5];

int[] array = new int[n];
array[0]=a; array[1]=b; array[2]=c; array[3]=d; array[4]=e; array[5]=f;
array[6]=a; array[7]=b; array[8]=c; array[9]=d; array[10]=e; array[11]=f;
array[12]=a; array[13]=b; array[14]=c; // .. and so on

But how can I do this if I don't know the lengths yet? 但如果我不知道长度,我怎么能这样做呢? I assume I would have to use a loop of some kind, but I'm not sure how to write one. 我假设我必须使用某种循环,但我不知道如何写一个。 Or is there some built-in way to repeat an array in Java, like some other languages have? 或者是否有一些内置的方法在Java中重复数组,就像其他一些语言一样?

This implementation is much cleaner and faster than the others shown here. 此实现比此处显示的其他实现更清晰,更快捷。

public static <T> T[] repeat(T[] arr, int newLength) {
    T[] dup = Arrays.copyOf(arr, newLength);
    for (int last = arr.length; last != 0 && last < newLength; last <<= 1) {
        System.arraycopy(dup, 0, dup, last, Math.min(last << 1, newLength) - last);
    }
    return dup;
}

Theory 理论

System.arraycopy is a native call. System.arraycopy是本机调用。 Therefore it is very fast but it doesn't mean it is the fastest way. 因此它非常快,但并不意味着它是最快的方式。

Every other solution copys the array element by element. 每个其他解决方案都按元素复制数组元素。 My solution copys larger blocks. 我的解决方案复制更大的块。 Every iteration duplicates the existing elements in the array which means the loop will run at most log2(n) times. 每次迭代都会复制数组中的现有元素,这意味着循环最多只能运行log2(n)次。

Profiling reports 分析报告

Here is my benchmark code to reproduce the results: 以下是重现结果的基准代码:

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;

@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@Measurement(iterations = 10, timeUnit = TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Threads(1)
@Warmup(iterations = 5, timeUnit = TimeUnit.NANOSECONDS)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark {

  private static final String[] TEST_ARRAY = { "a", "b", "c", "d", "e", "f" };
  private static final int NEW_LENGTH = 10_000;

  @Benchmark
  public String[] testMethod() {
    String[] dup = Arrays.copyOf(TEST_ARRAY, NEW_LENGTH);
    for (int last = TEST_ARRAY.length; last != 0 && last < NEW_LENGTH; last <<= 1) {
      System.arraycopy(dup, 0, dup, last, Math.min(last << 1, NEW_LENGTH) - last);
    }
    return dup;
  }

  @Benchmark
  public String[] testMethod1() {
    String[] arr = new String[NEW_LENGTH];
    for (int i = 0; i < NEW_LENGTH; i++) {
      arr[i] = TEST_ARRAY[i % TEST_ARRAY.length];
    }
    return arr;
  }

  @Benchmark
  public String[] testMethod2() {
    List<String> initialLetters = Arrays.asList(TEST_ARRAY);
    List<String> results = new ArrayList<>();
    int indexOfLetterToAdd = 0;
    for (int i = 0; i < 10000; i++) {
      results.add(initialLetters.get(indexOfLetterToAdd++));
      if (indexOfLetterToAdd == initialLetters.size()) {
        indexOfLetterToAdd = 0;
      }
    }
    return results.toArray(new String[results.size()]);
  }

  @Benchmark
  public String[] testMethod3() {
    String result[] = new String[NEW_LENGTH];
    for (int i = 0, j = 0; i < NEW_LENGTH && j < TEST_ARRAY.length; i++, j++) {
      result[i] = TEST_ARRAY[j];
      if (j == TEST_ARRAY.length - 1) {
        j = -1;
      }
    }
    return result;
  }

  @Benchmark
  public String[] testMethod4() {
    String[] result = Stream.iterate(TEST_ARRAY, x -> x).flatMap(x -> Stream.of(TEST_ARRAY)).limit(NEW_LENGTH)
        .toArray(String[]::new);
    return result;
  }
}

Results 结果

Benchmark                Mode  Cnt      Score      Error  Units
MyBenchmark.testMethod   avgt   30   4154,553 ±   11,242  ns/op
MyBenchmark.testMethod1  avgt   30  19273,717 ±  235,547  ns/op
MyBenchmark.testMethod2  avgt   30  71079,139 ± 2686,136  ns/op
MyBenchmark.testMethod3  avgt   30  18307,368 ±  202,520  ns/op
MyBenchmark.testMethod4  avgt   30  68898,278 ± 2488,104  ns/op

EDIT 编辑

I rephrased this question and answered it with more precise benchmarks as it was suggested. 我重新提出了这个问题,并按照建议的更精确的基准回答了这个问题。 Fastest way to create new array with length N and fill it by repeating a given array 创建长度为N的新数组的最快方法,并通过重复给定数组来填充它

You can try like this 你可以这样试试

String arr[] = {"a", "b", "c", "d", "e", "f"};
int repeat = 10000;
String result[] = new String[repeat];
for(int i=0, j=0; i<repeat && j<arr.length; i++, j++)
{
   result[i] = arr[j];
   if(j == arr.length -1)
         j = -1;
   System.out.println("array["+i+"] : "+result[i]);
}

I am assuming you know the size of the input, (eg you know that there are six elements in the input above. Let us name it iSize . Alternatively, you could find this using arr.length where arr is the input array.) 我假设您知道输入的大小,(例如,您知道上面的输入中有六个元素。让我们将其命名为iSize 。或者,您可以使用arr.length找到它,其中arr是输入数组。)

This might be a cleaner solution for the above. 对于上述情况,这可能是更清洁的解决方案。

for(int i=iSize; i<10000; i++)
    arr[i] = arr[i%iSize];
List<String> initialLetters = Arrays.asList("a", "b", "c", "d", "e", "f");
List<String> results = new ArrayList<>();
int indexOfLetterToAdd = 0;
for (int i=1;i<10000;i++){
    results.add(initialLetters.get(indexOfLetterToAdd++));
    if(indexOfLetterToAdd==initialLetters.size()){ //reset counter when necessary
        indexOfLetterToAdd=0;
    }
}
return results;

A very clean and fast implementation is like this with a little expanded and much readable form: 一个非常干净和快速的实现是这样的,有一点扩展和可读的形式:

public static String[] nLenArry(String[] inpArry, int n) {
    String[] output = new String[n];
    int length = inpArry.length;
    int position = 0;

    // Copy Iterations
    while (position < n-length) {
        System.arraycopy(inpArry, 0, output, position, length);
        position += length;
    }

    // Copy the last part
    System.arraycopy(inpArry, 0, output, position, n % length);

    return output;
}

Same code in more compact form: 相同的代码以更紧凑的形式:

public static String[] nLenArry(String[] inpArry, int n) {
    String[] output = new String[n];
    int position = 0;
    while (position < n - inpArry.length) {
        System.arraycopy(inpArry, 0, output, position, inpArry.length);
        position+=inpArry.length;
    }
    System.arraycopy(inpArry, 0, output, position, n % inpArry.length);
    return output;
}

Also, if you want to save some space, you can use this clever little trick and try implementing it as a new class: 此外,如果你想节省一些空间,你可以使用这个聪明的小技巧并尝试将其作为一个新类实现:

import java.util.AbstractList;

public class RepeatedArrayList<E> extends AbstractList<E> {
    private E[] arry;
    private int size;

    public RepeatedArrayList(E[] inpArry, int size) {
        this.arry = inpArry;
        this.size = size;
    }

    public E get(int position) {
        if (position >= 0 && position < size)
            return arry[position % arry.length];
        else throw new IndexOutOfBoundsException(
            "index " + position + " is negative or >= " + size
        );
    }

    public int size() {
        return this.size;
    }
}

After this all you need to do is the following code in your other classes 在此之后,您需要做的就是在其他类中使用以下代码

repeatedArry cst = new RepeatedArrayList(arr, 10000);

and

//use
cst.get(x);

//instead of 
arr[x];

This should help: 这应该有所帮助:

static int[] function(int[] array, int n)
{
    if(array == null)
    {
        throw new NullPointerException();
    }

    if(n < 0)
    {
        throw new RuntimeException();
    }

    int[] newArray = new int[n];
    int arraysize = array.length;
    int i = 0 , j = 0;

    int loop = n -  (n % arraysize);

    while(i < loop)
    {
        for(j = 0 ; j < arraysize; j++, i++)
        {
            newArray[i] = array[j];
        }
    }

    j = 0;
    while(i < n)
    {
        newArray[i++] = array[j++]; 
    }

    return newArray;
}

same answer in another didactic form, without specific function on array 另一个教学形式的相同答案,没有阵列上的特定功能

// INPUT
int[] input={1,2,3,4,5,6}; // new int[6];
int n=10;

// original size: you get it her
int size=input.length;

// final size : original size X repetition
int final_size=size*n;

int[] final_array=new int[final_size];

// we just copy in a loop, with % (modulus function)
for (int pos=0;pos<final_size;pos++)
    final_array[pos]=input[pos%size];

// OUTPUT : that's it
// => final_array

Assume that your n is known and your array is a primitive type and not an object (eg List) 假设您的n已知并且您的数组是基本类型而不是对象(例如List)

int fLen = input.length * n;
int[] outputArray = new int[fLen];
for ( int i = 0; i < n; i++) {
    System.arraycopy(input, 0, outputArray, i * input.length, input.length);
}

fLen is the final length of your output array fLen是输出数组的最终长度

Assume you don't know n 假设你不知道n

int[] outputArray2 = new int[input.length]; // at least can contain input once
System.arraycopy(input, 0, outputArray2, 0, input.length);
System.out.print("More? > (Y/N) ");
String ans = System.console().readLine();
while ( ans.equals("Y") || ans.equals("y") ) {
    int[] tmp = new int[outputArray2.length + input.length];
    System.arraycopy(outputArray2, 0, tmp, 0, outputArray2.length);
    System.arraycopy(input, 0, tmp, outputArray2.length, input.length);
    outputArray2 = tmp;
    System.out.print("More? > (Y/N) ");
    ans = System.console().readLine();
}

for ( int i = 0; i < outputArray2.length;i++)
    System.out.println("["+i+"] => " + outputArray2[i]);

Then you can use the outputArray as you want. 然后你可以根据需要使用outputArray。

I saw that others have implemented similar solutions as I (using lists, but not ArrayLists), but here is how I would approach the problem. 我看到其他人已经实现了类似的解决方案(使用列表,但不是ArrayLists),但这是我如何处理问题。 My Java is a little rusty, so I'm sure there are faster ways to do this, but here we go: 我的Java有点生疏,所以我确信有更快的方法可以做到这一点,但我们走了:

   char[] array = {'a','b','c','d','e','f'};
    ArrayList<Character> arrList = new ArrayList<Character>();

    System.out.println("How many elements in the new array?");
    Scanner kb = new Scanner(System.in);
    int length = kb.nextInt();

    for(int i = 0; i < length; i++){
        arrList.add(array[i%(array.length)]);
    }

    char[] finalArray = new char[length];
    for(int i = 0; i < length; i++){
        finalArray[i] = arrList.get(i);
    }

    System.out.println(finalArray);

Basically what I am doing is getting input as to how long the resultant array should be and then appending the elements of the original array to an ArrayList that many times. 基本上我正在做的是获取输入结果数组应该多长时间,然后多次将原始数组的元素附加到ArrayList。 The data types could be changed to work for any other data type, but since the question used chars in the array that's how I did mine. 数据类型可以更改为适用于任何其他数据类型,但由于问题使用数组中的字符,这就是我的方式。 Also, if you were okay with ending with an ArrayList instead of an array, you could drop the last for() loop. 此外,如果您可以使用ArrayList而不是数组结束,则可以删除最后一个for()循环。

After running this, my console displays: 运行此操作后,我的控制台显示:

How many elements in the new array?
10
abcdefabcd

If you don't know the input array size before the program runs, I would first implement it as an ArrayList so that it can be dynamically grown. 如果在程序运行之前你不知道输入数组大小,我首先将它实现为ArrayList,以便它可以动态增长。 Then, once the user stops entering new values for the input array, it could be converted to an array (unnecessary unless you NEED the array data type instead of an ArrayList) or it can be used as is. 然后,一旦用户停止为输入数组输入新值,它就可以转换为数组(除非您需要数组数据类型而不是ArrayList,否则不需要),或者它可以按原样使用。 After that you can use the same idea as above to create the output array. 之后,您可以使用与上面相同的想法来创建输出数组。 Code example as follows: 代码示例如下:

   ArrayList<Character> inputArr = new ArrayList<Character>();
    ArrayList<Character> arrList = new ArrayList<Character>();
    Scanner kb = new Scanner(System.in);

    System.out.println("How many elements in the new array?");
    int length = kb.nextInt();

    System.out.print("Enter a value? (y/n): ");

    while(kb.next().equals("y")){
        System.out.print("Enter the value: ");
        inputArr.add(kb.next().charAt(0)); //in case the user inputs more than a char, only accepts the first char of the line
        System.out.print("Enter another value? (y/n): ");
    }
    System.out.println(inputArr);

    for(int i = 0; i < length; i++){
        arrList.add(inputArr.get(i%(inputArr.size())));
    }

    System.out.println(arrList);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM