How can I get to the iterator of an array? - java

I'd like to use the following class like so:
for(String device : new Devices())
{
//
}
If I provide direct access to the internal string array, then there is no problem:
for(String device : new Devices().getAllDevices()) //getAllDevices would be a String[]
{
//
}
But I just want to forward the iterator, which would be simple if AllDevices were an ArrayList.
public final class Devices implements Iterable<String>{
private static final String MyKindleFire = "123156448975312";
private static final String[] AllDevices = new String[]{MyKindleFire};
#Override
public Iterator<String> iterator() {
// if AllDevices were an array list, this would be possible
// but how should I do this for an array?
return AllDevices.iterator();
}
}
This works, but I'd like to know a better way if possible:
#Override
public Iterator<String> iterator() {
return Arrays.asList(AllDevices).iterator();
}

Unfortunately, you cannot do it without converting your array to List<T>: iterating over arrays with the "foreach" version of the for loop is a "compiler trick", i.e. something the compiler knows and does internally.
An ability to use primitives in "foreach" loops is an indirect indication that Iterator<T> is not used there, because Java generics cannot be used with primitive types.

String[] someArray = ....;
List<String> someList = java.util.Arrays.asList(someArray);
someList.iterator();
I think this is the only way to get an Iterator of an array in pure java.
If you are using apache commons-collections you can simply use:
org.apache.commons.collections.IteratorUtils.arrayIterator(Object[])
See http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections/IteratorUtils.html

You could use Guava's Iterators.forArray(T...) to make an iterator.
Alternatively, make an Iterable out of your array (e.g. with Arrays.asList(T...)) and return its .iterator().

Related

Collections.sort throws UnsupportedOperationException while sorting a List after guava's Lists.transform function in Java?

I have a list which I transform using guava's Lists.transform function. Later, when I try to sort the list using Collections.sort(), I get an UnsupportedOperationException.
My code look's like this:
private List<SelectItemInfo> convertToSelectItemList(
final List<String> dataOwnersOfActiveQualifiers)
{
final List<SelectItemInfo> dataOwnersSelectItemList = transform(dataOwnersOfActiveQualifiers,
new Function<String, SelectItemInfo>()
{
public SelectItemInfo apply(final String input)
{
final Employee employee = getLdapQuery().findEmployeesByIdOrLogin(input);
return new SelectItemInfo(input, employee.toStringNameSurname());
}
});
Collections.sort(dataOwnersSelectItemList, this.comparator);
return dataOwnersSelectItemList;
}
I am not sure why I am getting this error.
Collections.sort needs to be able to call set on the list and have it do the expected thing. The list returned by transform doesn't support its set method (it's a "read only" list).
An easy fix is to create a new list and sort that
List<SelectItemInfo> sortedCopy = new ArrayList(dataOwnersSelectItemList);
Collections.sort(sortedCopy, this.comparator);
// use sortedCopy
Streams are a better solution

Is there a way of foreaching an Iterator in Java?

Java now has a convenient way to foreach a Collection eg.
for (MyClass c : aCollection) {
...
}
Is there something similarly elegant to foreach an Iterator or am I stuck with :
for (;it.hasNext();) {
MyClass c = it.next();
...
}
Update : for people who find this a strange question, I'm used to Python where
for x in xs :
f(x)
works whether xs is a collection OR an iterator (or even a generator). I was kind of caught out and surprised that Java didn't work like this.
I'm implementing a library where I'm returning iterators to some internal collections rather than the collections themselves. But I'm now concerned that this will force the users of my library back to using an older / uglier way of traversing than the foreach. Does this effectively deprecate iterators if people are used to using the foreach construct?
Well, apart from arrays which are a peculiar beast, the "extended for" loop you use here is just a result of the class implementing Iterable. And this interface only provides one method which is to return an... Iterator.
Which means that if you write in code:
for (final Foo foo: someInstanceImplementingIterableOfFoo) {
doSomethingWith(foo);
}
it is in fact equivalent to:
final Iterator<Foo> iterator = someInstanceImplementingIterableOfFoo.iterator();
Foo foo;
while (iterator.hasNext()) {
foo = iterator.next();
doSomethingWith(foo);
}
So, the answer really is no, no elegant way...
That is, unless you use Java 8. It has added forEachRemaining() on Iterator.
Or just create a utility class:
public final class IteratorWrap<T>
implements Iterable<T>
{
private final Iterator<T> iterator;
public static <X> IteratorWrap<X> wrap(final Iterator<X> iterator)
{
return new IteratorWrap<>(iterator);
}
private IteratorWrap(final Iterator<T> iterator)
{
this.iterator = Objects.requireNonNull(iterator);
}
#Override
public Iterator<T> iterator()
{
return iterator;
}
}
In code you'd then just:
for (final Foo foo: IteratorWrap.wrap(iteratorOfX))
doSomethingWith(foo);
Well, since you want something modern, using Java 8 you can do
Iterator<String> names = Arrays.asList("one","two","three").iterator();
for(String name : (Iterable<String>) () -> names) {
System.out.println(name);
}
Since the for-loop expects an Iterable Object, with this technique you can provide an Iterable out of an Iterator by using a lambda expression.
As mentioned by fge in another answer, though, this is equivalent to the following Java 8 expression using method references and avoiding the creation of the Iterable:
names.forEachRemaining(System.out::println);
So, you can pack your logic into a Consumer and solve your problem.
Java's "enhanced" for loop requires that the target to be iterated must implement Iterable. But if you have only an Iterator, which doesn't implement Iterable, there is no built-in way of using the Iterator as the target of a foreach loop in Java.
If you can't use Java 8, you can create an adapter class that wraps the Iterator, implements Iterable, and returns the wrapped iterator in the iterator() method.
class IterableIterator<T> implements Iterable<T>
{
private Iterator<T> iterator;
public IterableIterator(Iterator<T> iterator)
{
this.iterator = iterator;
}
#Override
public Iterator<T> iterator()
{
return iterator;
}
}
Then, if you have an Iterator, you can use it like this:
Iterator<MyClass> itr = getIteratorSomehow();
for (MyClass obj : new IterableIterator<MyClass>(itr))
{
// ...
}
Iterator<String> names = Arrays.asList("one", "two", "three").iterator();
String foo;
while((foo= Iterators.getNext(names, null))!=null){
System.out.println(foo);
}

Java: Apply Callback to Array Values

I'm looking for a simple way to apply a callback method to each element in a String array. For instance in PHP I can make all elements in an array like this:
$array = array_map('strtolower', $array);
Is there a simple way to accomplish this in Java?
First, object arrays in Java are vastly inferior to Lists, so you should really use them instead if possible. You can create a view of a String[] as a List<String> using Arrays.asList.
Second, Java doesn't have lambda expressions or method references yet, so there's no pretty way to do this... and referencing a method by its name as a String is highly error prone and not a good idea.
That said, Guava provides some basic functional elements that will allow you to do what you want:
public static final Function<String, String> TO_LOWER =
new Function<String, String>() {
public String apply(String input) {
return input.toLowerCase();
}
};
// returns a view of the input list with each string in all lower case
public static List<String> toLower(List<String> strings) {
// transform in Guava is the functional "map" operation
return Lists.transform(strings, TO_LOWER);
}
Unlike creating a new array or List and copying the lowercase version of every String into it, this does not iterate the elements of the original List when created and requires very little memory.
With Java 8, lambda expressions and method references should finally be added to Java along with extension methods for higher-order functions like map, making this far easier (something like this):
List<String> lowerCaseStrings = strings.map(String#toLowerCase);
There's no one-liner using built-in functionality, but you can certainly match functionality by iterating over your array:
String[] arr = new String[...];
...
for(int i = 0; i < arr.length; i++){
arr[i] = arr[i].toLowerCase();
}
You could use reflection:
String[] map(java.lang.reflect.Method method, String[] array) {
String[] new_array = new String[array.length];
for (int i = 0; i < array.length; i++) new_array[i] = (String)method.invoke(null, new Object[]{array[i]});
return new_array;
}
Then you just need to declare a static method somewhere and get a reference to it using the reflection API.

List of Lists of Lists

I'm new to Java and I need to make a list of lists of lists. I could do it in python because an element of a list can be a list so in an embedded list list[0] would refer to a list and list[0][0] would refer to the zeroeth element of the embedded list. Is there any easy way to implement this behavior in java?
All the other answers are technically correct, but IMHO if you implement a rough List of Lists of Lists you are not treating your data at the right level of abstraction. For example I am pretty sure that a List of Lists already means "something" in your business domain. Encapsulate this "something" in another object so you can just have a List<Something> instead of a difficult to use and maintain List<List<List<Object>>>.
As Mario says, you probably need to abstract out your data a little further. But, the following will do what you need.
In Java you would so something like:
List<List<List<Object>>> listOfListsOfLists =new ArrayList<List<List<Object>>>();
Then to access the items, you would use:
listOfListsOfLists.get(a).get(b).get(c);
Or, to iterate over everything:
for (List<List<Object>> list2: listOfListsOfLists) {
for (List<Object> list1: list2) {
for (Object o: list1) {
// use `o`
}
}
}
Since all of these answers make me barf, can I just add the suggestion that you either
Create a data type to express your data while encapsulating the details of the structure, or at least
Create a key type that wraps an int[] (but overrides equals and hashCode properly) and use a HashMap instead? It's typically rare that your whole 3-dimensional structure will be filled up much anyway.
Even better you could encapsulate that map and use varargs for clean access.
public class NDimensionalArray<V> {
private final int dimensions;
private final Map<Key, V> values = new HashMap<Key, V>();
private NDimensionalArray(int dimensions) {
this.dimensions = dimensions;
}
public V get(int... indices) {
checkIndices(indices);
return values.get(new Key(indices));
}
public void set(V value, int... indices) {
checkIndices(indices);
values.put(new Key(indices), value);
}
private void checkIndices(int[] indices) {
if ( indices.length != dimensions ) {
throw new IllegalArgumentException();
}
}
private static final class Key {
private final int[] indices;
private Key(int[] indices) {
this.indices = indices;
}
#Override
public int hashCode() {
return Arrays.hashCode(indices);
}
#Override
public boolean equals(Object obj) {
return Arrays.equals(indices, ((Key)obj).indices);
}
}
}
If people have examples of established collections libraries that already do this sort of thing, let me know and I'll add links.
While it is certainly true that you can construct a List<List<List<whatever>>> in Java, I can't help but wonder, Why do you want to do this? Not that it's inconceivable that this is the best solution to your problem, but wow, like why?
I guess I could imagine something like
public class Employee ...
List<Employee> store; // all the employees in a store
List<List<Employee>> city; // all the store lists for a city
List<List<List<Employee>>> nation; // all the store lists for the nation
But would you really want to process it that way? I don't know, it depends on what you need to do with it.
A comprehensive example showing List-of-List with collections and generics (Java 1.5+)
// declare the list of lists
List<List<String>> listOfListOfStrings = new ArrayList<List<String>>();
// populate
List<String> listOfStrings = new ArrayList<String>(); // one inner list
listOfStrings.add("one-one");
listOfStrings.add("one-two");
listOfListOfStrings.add(listOfStrings);
listOfStrings = new ArrayList<String>(); // and another one
listOfStrings.add("two-one");
listOfStrings.add("two-two");
listOfListOfStrings.add(listOfStrings);
// access
String oneOne = listOfListOfStrings.get(0).get(0); // first element of first inner list
String twoTwo = listOfListOfStrings.get(1).get(1); // second element of second inner list

How to lowercase every element of a collection efficiently?

What's the most efficient way to lower case every element of a List or Set?
My idea for a List:
final List<String> strings = new ArrayList<String>();
strings.add("HELLO");
strings.add("WORLD");
for(int i=0,l=strings.size();i<l;++i)
{
strings.add(strings.remove(0).toLowerCase());
}
Is there a better, faster way? How would this example look like for a Set? As there is currently no method for applying an operation to each element of a Set (or List) can it be done without creating an additional temporary Set?
Something like this would be nice:
Set<String> strings = new HashSet<String>();
strings.apply(
function (element)
{ this.replace(element, element.toLowerCase();) }
);
Thanks,
Yet another solution, but with Java 8 and above:
List<String> result = strings.stream()
.map(String::toLowerCase)
.collect(Collectors.toList());
This seems like a fairly clean solution for lists. It should allow for the particular List implementation being used to provide an implementation that is optimal for both the traversal of the list--in linear time--and the replacing of the string--in constant time.
public static void replace(List<String> strings)
{
ListIterator<String> iterator = strings.listIterator();
while (iterator.hasNext())
{
iterator.set(iterator.next().toLowerCase());
}
}
This is the best that I can come up with for sets. As others have said, the operation cannot be performed in-place in the set for a number of reasons. The lower-case string may need to be placed in a different location in the set than the string it is replacing. Moreover, the lower-case string may not be added to the set at all if it is identical to another lower-case string that has already been added (e.g., "HELLO" and "Hello" will both yield "hello", which will only be added to the set once).
public static void replace(Set<String> strings)
{
String[] stringsArray = strings.toArray(new String[0]);
for (int i=0; i<stringsArray.length; ++i)
{
stringsArray[i] = stringsArray[i].toLowerCase();
}
strings.clear();
strings.addAll(Arrays.asList(stringsArray));
}
You can do this with Google Collections:
Collection<String> lowerCaseStrings = Collections2.transform(strings,
new Function<String, String>() {
public String apply(String str) {
return str.toLowerCase();
}
}
);
If you are fine with changing the input list here is one more way to achieve it.
strings.replaceAll(String::toLowerCase)
Well, there is no real elegant solution due to two facts:
Strings in Java are immutable
Java gives you no real nice map(f, list) function as you have in functional languages.
Asymptotically speaking, you can't get a better run time than your current method. You will have to create a new string using toLowerCase() and you will need to iterate by yourself over the list and generate each new lower-case string, replacing it with the existing one.
Try CollectionUtils#transform in Commons Collections for an in-place solution, or Collections2#transform in Guava if you need a live view.
This is probably faster:
for(int i=0,l=strings.size();i<l;++i)
{
strings.set(i, strings.get(i).toLowerCase());
}
I don't believe it is possible to do the manipulation in place (without creating another Collection) if you change strings to be a Set. This is because you can only iterate over the Set using an iterator or a for each loop, and cannot insert new objects whilst doing so (it throws an exception)
Referring to the ListIterator method in the accepted (Matthew T. Staebler's) solution. How is using the ListIterator better than the method here?
public static Set<String> replace(List<String> strings) {
Set<String> set = new HashSet<>();
for (String s: strings)
set.add(s.toLowerCase());
return set;
}
I was looking for similar stuff, but was stuck because my ArrayList object was not declared as GENERIC and it was available as raw List type object from somewhere. I was just getting an ArrayList object "_products". So, what I did is mentioned below and it worked for me perfectly ::
List<String> dbProducts = _products;
for(int i = 0; i<dbProducts.size(); i++) {
dbProducts.add(dbProducts.get(i).toLowerCase());
}
That is, I first took my available _products and made a GENERIC list object (As I were getting only strings in same) then I applied the toLowerCase() method on list elements which was not working previously because of non-generic ArrayList object.
And the method toLowerCase() we are using here is of String class.
String java.lang.String.toLowerCase()
not of ArrayList or Object class.
Please correct if m wrong. Newbie in JAVA seeks guidance. :)
Using JAVA 8 parallel stream it becomes faster
List<String> output= new ArrayList<>();
List<String> input= new ArrayList<>();
input.add("A");
input.add("B");
input.add("C");
input.add("D");
input.stream().parallel().map((item) -> item.toLowerCase())
.collect(Collectors.toCollection(() -> output));

Categories

Resources