Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a List<String> to a List<Integer> (or any class that extends Number)

I want to create a very generic utility method to take any Collection and convert it into a Collection of a user selectable class that extends from Number (Long, Double, Float, Integer, etc.)

I came up with this code that uses Google Collections to transform the Collection and to return an Immutable List.

import java.util.List;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
/**
     * Takes a {@code List<String>} and transforms it into a list of the
     * specified {@code clazz}.
     * 
     * @param <T>
     * @param stringValues
     *            the list of Strings to be used to create the list of the
     *            specified type
     * @param clazz
     *            must be a subclass of Number. Defines the type of the new List
     * @return
     */
    public static <T extends Number> List<T> toNumberList(List<String> stringValues, final Class<T> clazz) {
        List<T> ids = Lists.transform(stringValues, new Function<String, T>() {
            @SuppressWarnings("unchecked")
            @Override
            public T apply(String from) {
                T retVal = null;
                if (clazz.equals(Integer.class)) {
                    retVal = (T) Integer.valueOf(from);
                } else if (clazz.equals(Long.class)) {
                    retVal = (T) Long.valueOf(from);
                } else if (clazz.equals(Float.class)) {
                    retVal = (T) Float.valueOf(from);
                } else if (clazz.equals(Double.class)) {
                    retVal = (T) Double.valueOf(from);
                } else {
                    throw new RuntimeException(String.format("Type %s is not supported (yet)", clazz.getName()));
                }
                return retVal;
            }
        });
        return ImmutableList.copyOf(ids);
    }

It can be used like this:

// Convert List<String> to List<Long>
List<Long> ids = MiscUtils.toNumberList(productIds, Long.class);

Is my code overkill or how would you simplify it and at the same time keep it generic enough?

like image 722
Eliseo Soto Avatar asked Nov 05 '10 18:11

Eliseo Soto


People also ask

How to convert a list of string to list of int?

The following code demonstrates its usage: Alternatively, you can use the List<T>.ConvertAll () method to convert a list of one type to another type. We can use it to convert a List of String to a List of Int as follows. That’s all about converting a List of String to a List of Int in C#.

How to convert list<string> to list<int> in LINQ?

We can use LINQ’s Select () method to convert List<string> to List<int> in C#. The Select () method projects each element of a sequence into a new form. The following code demonstrates its usage: Alternatively, you can use the List<T>.ConvertAll () method to convert a list of one type to another type.

How to convert a list of one type to another type?

The Select () method projects each element of a sequence into a new form. The following code demonstrates its usage: Alternatively, you can use the List<T>.ConvertAll () method to convert a list of one type to another type. We can use it to convert a List of String to a List of Int as follows.

How do you convert a string to an integer in C?

Sometimes we can have a list containing strings but the strings themselves are numbers and closing quotes. In such a list we want to convert the string elements into actual integers. The int function takes in parameters and converts it to integers if it is already a number.


1 Answers

I think the most important aspect of this code is the Function as opposed to the method itself. I also don't think it makes sense to switch over the subclasses you allow in the Function body, as you already know what type of Number you want to return at the time the Function is created. It's also slightly problematic that your method fails if given, say, BigInteger.class.

Given this, what I would do is create a utility class (let's call it Numbers) and provide methods on it that each return a Function (which can be an enum singleton) for parsing a String as a specific type of Number. That is:

public class Numbers {
  public static Function<String, Integer> parseIntegerFunction() { ... }
  public static Function<String, Long> parseLongFunction() { ... }
  ...
}

They could each be implemented something like this:

public static Function<String, Integer> parseIntegerFunction() {
  return ParseIntegerFunction.INSTANCE;
}

private enum ParseIntegerFunction implements Function<String, Integer> {
  INSTANCE;

  public Integer apply(String input) {
    return Integer.valueOf(input);
  }

  @Override public String toString() {
    return "ParseIntegerFunction";
  }
}

This can then be used however users want:

List<String> strings = ...
List<Integer> integers = Lists.transform(strings, Numbers.parseIntegerFunction());

This approach has quite a few advantages over yours:

  • Doesn't require any switching in the Function... we know what type of number we're creating and just do that. Faster.
  • Is more flexible, in that each Function can be used wherever... users aren't forced to use it the way your method does (copying the transformed values into an ImmutableList.
  • You only create the Functions you actually want to allow. If there's no BigInteger parsing function, users just can't call that, as opposed to having it be completely legal to do that at compile time and then fail at runtime like in your example.

As a side note, I'd recommend making the return type of any method that returns an ImmutableList be ImmutableList rather than List... it provides information that is useful to clients of the method.

Edit:

If you really need something more dynamic (i.e. you want classes that have an instance of some Class<T extends Number> to be able to transform Strings to that Number type) you could also add a lookup method like:

public static <T extends Number> Function<String, T> parseFunctionFor(Class<T> type) {
  // lookup the function for the type in an ImmutableMap and return it
}

This has the same problems as your original method, though, if there's a Number subclass that you don't provide a Function for. It also doesn't seem like there would be many situations where this would be useful.

like image 74
ColinD Avatar answered Oct 29 '22 01:10

ColinD