Fastest way to set all values of an array?

后端 未结 14 2250
悲哀的现实
悲哀的现实 2020-12-04 17:47

I have a char [], and I want to set the value of every index to the same char value.
There is the obvious way to do it (iteration):

<         


        
相关标签:
14条回答
  • 2020-12-04 17:47

    As another option and for posterity I was looking into this recently and found a solution that allows a much shorter loop by handing some of the work off to the System class, which (if the JVM you're using is smart enough) can be turned into a memset operation:-

    /*
     * initialize a smaller piece of the array and use the System.arraycopy 
     * call to fill in the rest of the array in an expanding binary fashion
     */
    public static void bytefill(byte[] array, byte value) {
      int len = array.length;
    
      if (len > 0){
        array[0] = value;
      }
    
      //Value of i will be [1, 2, 4, 8, 16, 32, ..., len]
      for (int i = 1; i < len; i += i) {
        System.arraycopy(array, 0, array, i, ((len - i) < i) ? (len - i) : i);
      }
    }
    

    This solution was taken from the IBM research paper "Java server performance: A case study of building efficient, scalable Jvms" by R. Dimpsey, R. Arora, K. Kuiper.

    Simplified explanation

    As the comment suggests, this sets index 0 of the destination array to your value then uses the System class to copy one object i.e. the object at index 0 to index 1 then those two objects (index 0 and 1) into 2 and 3, then those four objects (0,1,2 and 3) into 4,5,6 and 7 and so on...

    Efficiency (at the point of writing)

    In a quick run through, grabbing the System.nanoTime() before and after and calculating a duration I came up with:-

    • This method : 332,617 - 390,262 ('highest - lowest' from 10 tests)
    • Float[] n = new Float[array.length]; //Fill with null : 666,650
    • Setting via loop : 3,743,488 - 9,767,744 ('highest - lowest' from 10 tests)
    • Arrays.fill : 12,539,336

    The JVM and JIT compilation

    It should be noted that as the JVM and JIT evolves, this approach may well become obsolete as library and runtime optimisations could reach or even exceed these numbers simply using fill(). At the time of writing, this was the fastest option I had found. It has been mentioned this might not be the case now but I have not checked. This is the beauty and the curse of Java.

    0 讨论(0)
  • 2020-12-04 17:52

    See Arrays.fill method:

    char f = '+';
    char [] c = new char [50];
    Arrays.fill(c, f);
    
    0 讨论(0)
  • 2020-12-04 17:54

    Arrays.fill might suit your needs

    0 讨论(0)
  • 2020-12-04 17:55

    Use Arrays.fill

      char f = '+';
      char [] c = new char [50];
      Arrays.fill(c, f)
    
    0 讨论(0)
  • 2020-12-04 17:58

    As of Java-8, there are four variants of the setAll method which sets all elements of the specified array, using a provided generator function to compute each element.

    Of those four overloads only three of them accept an array of primitives declared as such:


    • setAll(double[] array, IntToDoubleFunction generator)

    • setAll(int[] array, IntUnaryOperator generator)

    • setAll(long[] array, IntToLongFunction generator)

    Examples of how to use the aforementioned methods:

    // given an index, set the element at the specified index with the provided value
    double [] doubles = new double[50];
    Arrays.setAll(doubles, index -> 30D);
    
    // given an index, set the element at the specified index with the provided value
    int [] ints = new int[50];
    Arrays.setAll(ints, index -> 60);
    
     // given an index, set the element at the specified index with the provided value
    long [] longs = new long[50];
    Arrays.setAll(longs, index -> 90L);
    

    The function provided to the setAll method receives the element index and returns a value for that index.

    you may be wondering how about characters array?

    This is where the fourth overload of the setAll method comes into play. As there is no overload that consumes an array of character primitives, the only option we have is to change the declaration of our character array to a type Character[].

    If changing the type of the array to Character is not appropriate then you can fall back to the Arrays.fill method.

    Example of using the setAll method with Character[]:

    // given an index, set the element at the specified index with the provided value
    Character[] character = new Character[50];
    Arrays.setAll(characters, index -> '+'); 
    

    Although, it's simpler to use the Arrays.fill method rather than the setAll method to set a specific value.

    The setAll method has the advantage that you can either set all the elements of the array to have the same value or generate an array of even numbers, odd numbers or any other formula:

    e.g.

    int[] evenNumbers = new int[10]; 
    Arrays.setAll(evenNumbers, i -> i * 2);
    

    There's also several overloads of the parallelSetAll method which is executed in parallel, although it's important to note that the function passed to the parallelSetAll method must be side-effect free.

    Conclusion

    If your goal is simply to set a specific value for each element of the array then using the Arrays.fill overloads would be the most appropriate option. However, if you want to be more flexible or generate elements on demand then using the Arrays.setAll or Arrays.parallelSetAll (when appropriate) would be the option to go for.

    0 讨论(0)
  • 2020-12-04 17:58

    You could use arraycopy but it depends on whether you can predefine the source array, - do you need a different character fill each time, or are you filling arrays repeatedly with the same char?

    Clearly the length of the fill matters - either you need a source that is bigger than all possible destinations, or you need a loop to repeatedly arraycopy a chunk of data until the destination is full.

        char f = '+';
        char[] c = new char[50];
        for (int i = 0; i < c.length; i++)
        {
            c[i] = f;
        }
    
        char[] d = new char[50];
        System.arraycopy(c, 0, d, 0, d.length);
    
    0 讨论(0)
提交回复
热议问题