简体   繁体   中英

How to Shrink array to specified length in java keeping elements uniformaly distributed?

I have source array, and I want to generate new array from the source array by removing a specified number of elements from the source array, I want the elements in the new array to cover as much as possible elements from the source array (the new elements are uniformly distributed over the source array) and keeping the first and last elements the same (if any).

I tried this :

public static void printArr(float[] arr)
    {
        for (int i = 0; i < arr.length; i++)
            System.out.println("arr[" + i + "]=" + arr[i]);

    }
public static float[] removeElements(float[] inputArr , int numberOfElementToDelete)
    {
       float [] new_arr = new float[inputArr.length - numberOfElementToDelete];
        int f = (inputArr.length  ) / numberOfElementToDelete;
        System.out.println("f=" + f);
        if(f == 1)
        {
            f = 2;
            System.out.println("f=" + f);
        }

       int j = 1 ;
        for (int i = 1; i < inputArr.length ; i++)
        {
            if( (i + 1) % f != 0)
            {

                System.out.println("i=" + i + "   j= " + j);
                if(j < new_arr.length)
                {
                    new_arr[j] = inputArr[i];
                    j++;
                }

            }

        }

        new_arr[0] = inputArr[0];
        new_arr[new_arr.length - 1] = inputArr[inputArr.length - 1];
        return new_arr;
    }
public static void main(String[] args)
    {

        float [] a = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
        a = removeElements(a, 6);
        printArr(a);
    }

I have made a test for(removeElements(a, 5) and removeElements(a, 4) and removeElements(a, 3)) but removeElements(a, 6); gave :

 arr[0]=1.0
arr[1]=3.0
arr[2]=5.0
arr[3]=7.0
arr[4]=9.0
arr[5]=11.0
arr[6]=13.0
arr[7]=15.0
arr[8]=0.0
arr[9]=16.0

the problem is (arr[8]=0.0) it must take a value .. How to solve this? is there any code that can remove a specified number of elements (and keep the elements distributed over the source array without generating zero in some elements)?

EDIT :

examples : removeElements(a, 1) ==> remove one element from the middle (7) {1,2,3,4,5,6,7,9,10,11,12,13,14,15,16}

removeElements(a, 2) ==> remove two elements at indexes (4,19) or (5,10) or (4,10) (no problem)

removeElements(a, 3) ==> remove three elements at indexes (4,9,14) or (4,10, 15) or(no problem also)

removeElements(a, 4) ==> remove four elements at indexes (3,7,11 , 15) or ( 3 ,7,11,14) for example .. what I want is if I draw the values in the source array on (chart on Excel for example) and I draw the values from the new array , I must get the same line (or close to it).

I think the main problem in your code is that you are binding the selection to

(inputArr.length  ) / numberOfElementToDelete

This way you are not considering the first and the last elements that you don't want to remove.

An example: if you have an array of 16 elements and you want to delete 6 elements it means that the final array will have 10 elements but, since the first and the last are fixed, you'll have to select 8 elements out of the remaining 14. This means you'll have to select 8/14 (0,57) elements from the array (not considering the first and the last). This means that you can initialize a counter to zero, scan the array starting from the second and sum the value of the fraction to the counter, when the value of the counter reach a new integer number (ex. at the third element the counter will reach 1,14) you'll have an element to pick and put to the new array.

So, you can do something like this (pseudocode):

    int newLength = originalLength - toDelete;
    int toChoose = newLength - 2;
    double fraction = toChoose / (originalLength -2)
    double counter = 0;
    int threshold = 1;
    int newArrayIndex = 1;
    for(int i = 1; i < originalLength-1; i++){
        **counter += fraction;**            
        if(integerValueOf(counter) == threshold){
            newArray[newArrayIndex] = originalArray[i];
            threshold++;
            **newArrayIndex++;**
        }

     }
     newArray[0] = originalArray[0];
     newArray[newArray.length-1] = originalArray[originalArray.length-1];

You should check for the particular cases like originalArray of length 1 or removal of all the elements but I think it should work.

EDIT Here is a Java implementation (written on the fly so I didn't check for nulls etc.)

public class Test {

    public static void main(String[] args){
        int[] testArray = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
        int[] newArray = remove(testArray, 6);
        for(int i = 0; i < newArray.length; i++){
            System.out.print(newArray[i]+" ");
        }
    }

    public static int[] remove(int[] originalArray, int toDelete){  
        if(toDelete == originalArray.length){
            //avoid the removal of all the elements, save at least first and last
            toDelete = originalArray.length-2;
        }
        int originalLength = originalArray.length;
        int newLength = originalLength - toDelete;
        int toChoose = newLength - 2;
        int[] newArray = new int[newLength];
        double fraction = ((double)toChoose) / ((double)originalLength -2);
        double counter = 0;
        int threshold = 1;
        int newArrayIndex = 1;
        for(int i = 1; i < originalLength-1; i++){
            counter += fraction;            
            if(((int)counter) == threshold ||
                //condition added to cope with x.99999999999999999... cases 
               (i == originalLength-2 && newArrayIndex == newLength-2)){
                newArray[newArrayIndex] = originalArray[i];
                threshold++;
                newArrayIndex++;
            }           
         }
         newArray[0] = originalArray[0];
         newArray[newArray.length-1] = originalArray[originalArray.length-1];
         return newArray;
    }
}

Why cant you just initialize i=0

for (int i = 0; i < inputArr.length; i++) {
        if ((i + 1) % f != 0) {

Following is the output:

arr[0]=1.0
arr[1]=1.0
arr[2]=3.0
arr[3]=5.0
arr[4]=7.0
arr[5]=9.0
arr[6]=11.0
arr[7]=13.0
arr[8]=15.0
arr[9]=16.0

如果我理解正确,这就是水库采样 ,即从一个大型阵列中,通过随机选择创建一个小型阵列。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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