2

I am trying convert method to generic for CharSequence[] and for Set. Well I am not experienced in that.

This is the method where the second argument/return value should be generic (T). Is it possible?

private CharSequence[] remove(String string, CharSequence[] charSequences)
    {
        ArrayList<CharSequence> newArray = new ArrayList<CharSequence>();
        int foundPlace = -1;
        CharSequence[] v = charSequences;
        for (int i = 0; i < v.length; i++) {
            if (foundPlace != -1 && v[i].equals(string))
                foundPlace = i;
            else
                newArray.add(v[i]);
        }
        return newArray.toArray(new CharSequence[newArray.size()]);
    }

What I tried. Replaced everywhere where CharSequence[] occurs to T but it didn't work when I placed T in line T.length.


More clarification (sorry). I would like to convert second argument and return value to T - so everywhere where is CharSequence[] to T.

deadfish
  • 11,064
  • 11
  • 79
  • 125
  • Do you really mean to pass CharSequence[] in generics as second parameter to this method? That's not worth the effort! – Shishir Kumar Jul 21 '15 at 10:06
  • You can not create an array of generic types so your return statement won't work: return newArray.toArray(new CharSequence[newArray.size()]); – Anupam Saini Jul 21 '15 at 10:06
  • @ShishirKumar yes, make second argument to T – deadfish Jul 21 '15 at 10:08
  • @AnupamSaini, so mayber is there any other solution for this method? Any way? – deadfish Jul 21 '15 at 10:10
  • @deadfish You can't change `CharSequence[]` to `T` because of the fact that you are assuming `T` is an array by accessing its `length` parameter. You can try `T[]` which should work. The compiler doesn't know that `T` has a `length` member and that is why your code won't compile. – M. Shaw Jul 21 '15 at 10:28
  • If my understanding is correct you are trying to **remove** an element from a collection. You can easily wrap your array to a Set and call the underlying remove method – Anupam Saini Jul 21 '15 at 10:28
  • As @M.Shaw said, you don't have to replace `CharSequence[]` with `T`. You can try `T[]` instead. – Jason Sparc Jul 21 '15 at 10:38
  • Will you also make the whole class (containing the method) into generic? – Jason Sparc Jul 21 '15 at 10:43

5 Answers5

3

Maybe this is what you want:

private <T> T[] remove(T string, T[] charSequences)
    {
        ArrayList<T> newArray = new ArrayList<T>();
        int foundPlace = -1;
        T[] v = charSequences;
        for (int i = 0; i < v.length; i++) {
            if (foundPlace != -1 && v[i].equals(string))
                foundPlace = i;
            else
                newArray.add(v[i]);
        }
        @SuppressWarnings("unchecked")
        T[] ret = (T[]) Array.newInstance(v.getClass().getComponentType(), newArray.size());
        return newArray.toArray(ret);
    }

Or, if the containing class should also be generic of type T just remove <T> from above. So this line,

private <T> T[] remove(T string, T[] charSequences)

would then become,

private T[] remove(T string, T[] charSequences)

If the type of string doesn't matter, you may change its type to a plain Object,

private T[] remove(Object string, T[] charSequences)
    {
        ArrayList<T> newArray = new ArrayList<T>();
        int foundPlace = -1;
        T[] v = charSequences;
        for (int i = 0; i < v.length; i++) {
            if (foundPlace != -1 && v[i].equals(string))
                foundPlace = i;
            else
                newArray.add(v[i]);
        }
        ...
    }

You might also want to rename string to something else afterwards.


I should also note that in your logic, foundPlace will always be -1.

Jason Sparc
  • 662
  • 1
  • 7
  • 25
  • @Json Sparc you can not create a generic array the return statement of your code snippet won't work. http://stackoverflow.com/questions/2927391/whats-the-reason-i-cant-create-generic-array-types-in-java – Anupam Saini Jul 21 '15 at 10:58
1
  • You use an integer for foundPlace but a boolean is enough since you just test if it has been initialized and never use its value.
  • You don't even need this boolean, and your equals test is never evaluated since ̀foundPlace will always be equal to -1 (so the array you return is always a copy of charSequences)
  • You don't need an intermediary variable v, you can simply iterate over charSequences

Here is a version with Object, if it is what you are looking for :

private Object[] remove(Object val, Object[] array)
    {
        ArrayList<Object> newArray = new ArrayList<Object>();
        for (Object o : array)
            if(!o.equals(val))
                newArray.add(o);
        return newArray.toArray(new Object[newArray.size()]);
}
Paco
  • 43
  • 9
0

Generics and arrays can be a quite painful combination. I would stick to the List interface, if that is an option for you (ie. change return type to List and simply return newArray which would also be of type List).

Otherwise I recommend this post to better understand Generics and Arrays: How to create a generic array in Java?

EDIT: Oh, and you definitely don't want to replace "CharSequence[]" with "T", but possibly with "T[]" if you really need to work with arrays here.

Community
  • 1
  • 1
emu
  • 299
  • 2
  • 6
0

To implement a generic collection, use:

int length; // ...
T[] array = (T[])new Object[length];

So, the return statement will look like this:

return (T[])newArray.toArray(new Object[newArray.size()]);
sponge
  • 7,923
  • 13
  • 43
  • 77
0

Here is how you can implement a remove routine. Notice that you do not even need a separate remove method. I hope, I am not missing a use case that requires you to create a separate remove method.

package com.anupam;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class SO31535852 {
  public static void main(String args[]) {
    String[] arr = {"1", "2", "3"};

    // Create a copy of the orginal array if you do not want to modify it.
    Set<String> test = new HashSet<>(Arrays.asList(Arrays.copyOf(arr, arr.length)));

    // In fact you do not even need a remove method. I could not understand why you are using
    // foundPlace variable it's not doing much.
    System.out.println(remove("1", test));
    System.out.println(remove("1", test));
  }

  /**
   * Removes a specific value from the underling collection
   *
   * @param toRemove the object to be removed
   * @param myCollection the colelction from which to be removed
   * @return the removed value or null.
   */
  private static <T> T remove(T toRemove, Set<T> myCollection) {
    return myCollection.remove(toRemove) ? toRemove : null;
  }
}
Anupam Saini
  • 2,321
  • 2
  • 21
  • 29