How do I pick a random element from a set?
I'm particularly interested in picking a random element from a
HashSet or a LinkedHashSet, in Java.
Solutions for other languages are also welcome.
int size = myHashSet.size();
int item = new Random().nextInt(size); // In real life, the Random object should be rather more shared than this
int i = 0;
for(Object obj : myhashSet)
{
if (i == item)
return obj;
i++;
}
A somewhat related Did You Know:
There are useful methods in java.util.Collections for shuffling whole collections: Collections.shuffle(List<?>) and Collections.shuffle(List<?> list, Random rnd).
In Java 8:
static <E> E getRandomSetElement(Set<E> set) {
return set.stream().skip(new Random().nextInt(set.size())).findFirst().orElse(null);
}
Fast solution for Java using an ArrayList and a HashMap: [element -> index].
Motivation: I needed a set of items with RandomAccess properties, especially to pick a random item from the set (see pollRandom method). Random navigation in a binary tree is not accurate: trees are not perfectly balanced, which would not lead to a uniform distribution.
public class RandomSet<E> extends AbstractSet<E> {
List<E> dta = new ArrayList<E>();
Map<E, Integer> idx = new HashMap<E, Integer>();
public RandomSet() {
}
public RandomSet(Collection<E> items) {
for (E item : items) {
idx.put(item, dta.size());
dta.add(item);
}
}
#Override
public boolean add(E item) {
if (idx.containsKey(item)) {
return false;
}
idx.put(item, dta.size());
dta.add(item);
return true;
}
/**
* Override element at position <code>id</code> with last element.
* #param id
*/
public E removeAt(int id) {
if (id >= dta.size()) {
return null;
}
E res = dta.get(id);
idx.remove(res);
E last = dta.remove(dta.size() - 1);
// skip filling the hole if last is removed
if (id < dta.size()) {
idx.put(last, id);
dta.set(id, last);
}
return res;
}
#Override
public boolean remove(Object item) {
#SuppressWarnings(value = "element-type-mismatch")
Integer id = idx.get(item);
if (id == null) {
return false;
}
removeAt(id);
return true;
}
public E get(int i) {
return dta.get(i);
}
public E pollRandom(Random rnd) {
if (dta.isEmpty()) {
return null;
}
int id = rnd.nextInt(dta.size());
return removeAt(id);
}
#Override
public int size() {
return dta.size();
}
#Override
public Iterator<E> iterator() {
return dta.iterator();
}
}
This is faster than the for-each loop in the accepted answer:
int index = rand.nextInt(set.size());
Iterator<Object> iter = set.iterator();
for (int i = 0; i < index; i++) {
iter.next();
}
return iter.next();
The for-each construct calls Iterator.hasNext() on every loop, but since index < set.size(), that check is unnecessary overhead. I saw a 10-20% boost in speed, but YMMV. (Also, this compiles without having to add an extra return statement.)
Note that this code (and most other answers) can be applied to any Collection, not just Set. In generic method form:
public static <E> E choice(Collection<? extends E> coll, Random rand) {
if (coll.size() == 0) {
return null; // or throw IAE, if you prefer
}
int index = rand.nextInt(coll.size());
if (coll instanceof List) { // optimization
return ((List<? extends E>) coll).get(index);
} else {
Iterator<? extends E> iter = coll.iterator();
for (int i = 0; i < index; i++) {
iter.next();
}
return iter.next();
}
}
If you want to do it in Java, you should consider copying the elements into some kind of random-access collection (such as an ArrayList). Because, unless your set is small, accessing the selected element will be expensive (O(n) instead of O(1)). [ed: list copy is also O(n)]
Alternatively, you could look for another Set implementation that more closely matches your requirements. The ListOrderedSet from Commons Collections looks promising.
In Java:
Set<Integer> set = new LinkedHashSet<Integer>(3);
set.add(1);
set.add(2);
set.add(3);
Random rand = new Random(System.currentTimeMillis());
int[] setArray = (int[]) set.toArray();
for (int i = 0; i < 10; ++i) {
System.out.println(setArray[rand.nextInt(set.size())]);
}
List asList = new ArrayList(mySet);
Collections.shuffle(asList);
return asList.get(0);
This is identical to accepted answer (Khoth), but with the unnecessary size and i variables removed.
int random = new Random().nextInt(myhashSet.size());
for(Object obj : myhashSet) {
if (random-- == 0) {
return obj;
}
}
Though doing away with the two aforementioned variables, the above solution still remains random because we are relying upon random (starting at a randomly selected index) to decrement itself toward 0 over each iteration.
Clojure solution:
(defn pick-random [set] (let [sq (seq set)] (nth sq (rand-int (count sq)))))
Java 8+ Stream:
static <E> Optional<E> getRandomElement(Collection<E> collection) {
return collection
.stream()
.skip(ThreadLocalRandom.current()
.nextInt(collection.size()))
.findAny();
}
Based on the answer of Joshua Bone but with slight changes:
Ignores the Streams element order for a slight performance increase in parallel operations
Uses the current thread's ThreadLocalRandom
Accepts any Collection type as input
Returns the provided Optional instead of null
Perl 5
#hash_keys = (keys %hash);
$rand = int(rand(#hash_keys));
print $hash{$hash_keys[$rand]};
Here is one way to do it.
C++. This should be reasonably quick, as it doesn't require iterating over the whole set, or sorting it. This should work out of the box with most modern compilers, assuming they support tr1. If not, you may need to use Boost.
The Boost docs are helpful here to explain this, even if you don't use Boost.
The trick is to make use of the fact that the data has been divided into buckets, and to quickly identify a randomly chosen bucket (with the appropriate probability).
//#include <boost/unordered_set.hpp>
//using namespace boost;
#include <tr1/unordered_set>
using namespace std::tr1;
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
int main() {
unordered_set<int> u;
u.max_load_factor(40);
for (int i=0; i<40; i++) {
u.insert(i);
cout << ' ' << i;
}
cout << endl;
cout << "Number of buckets: " << u.bucket_count() << endl;
for(size_t b=0; b<u.bucket_count(); b++)
cout << "Bucket " << b << " has " << u.bucket_size(b) << " elements. " << endl;
for(size_t i=0; i<20; i++) {
size_t x = rand() % u.size();
cout << "we'll quickly get the " << x << "th item in the unordered set. ";
size_t b;
for(b=0; b<u.bucket_count(); b++) {
if(x < u.bucket_size(b)) {
break;
} else
x -= u.bucket_size(b);
}
cout << "it'll be in the " << b << "th bucket at offset " << x << ". ";
unordered_set<int>::const_local_iterator l = u.begin(b);
while(x>0) {
l++;
assert(l!=u.end(b));
x--;
}
cout << "random item is " << *l << ". ";
cout << endl;
}
}
Solution above speak in terms of latency but doesn't guarantee equal probability of each index being selected.
If that needs to be considered, try reservoir sampling. http://en.wikipedia.org/wiki/Reservoir_sampling. Collections.shuffle() (as suggested by few) uses one such algorithm.
Since you said "Solutions for other languages are also welcome", here's the version for Python:
>>> import random
>>> random.choice([1,2,3,4,5,6])
3
>>> random.choice([1,2,3,4,5,6])
4
Can't you just get the size/length of the set/array, generate a random number between 0 and the size/length, then call the element whose index matches that number? HashSet has a .size() method, I'm pretty sure.
In psuedocode -
function randFromSet(target){
var targetLength:uint = target.length()
var randomIndex:uint = random(0,targetLength);
return target[randomIndex];
}
PHP, assuming "set" is an array:
$foo = array("alpha", "bravo", "charlie");
$index = array_rand($foo);
$val = $foo[$index];
The Mersenne Twister functions are better but there's no MT equivalent of array_rand in PHP.
Icon has a set type and a random-element operator, unary "?", so the expression
? set( [1, 2, 3, 4, 5] )
will produce a random number between 1 and 5.
The random seed is initialized to 0 when a program is run, so to produce different results on each run use randomize()
In C#
Random random = new Random((int)DateTime.Now.Ticks);
OrderedDictionary od = new OrderedDictionary();
od.Add("abc", 1);
od.Add("def", 2);
od.Add("ghi", 3);
od.Add("jkl", 4);
int randomIndex = random.Next(od.Count);
Console.WriteLine(od[randomIndex]);
// Can access via index or key value:
Console.WriteLine(od[1]);
Console.WriteLine(od["def"]);
Javascript solution ;)
function choose (set) {
return set[Math.floor(Math.random() * set.length)];
}
var set = [1, 2, 3, 4], rand = choose (set);
Or alternatively:
Array.prototype.choose = function () {
return this[Math.floor(Math.random() * this.length)];
};
[1, 2, 3, 4].choose();
In lisp
(defun pick-random (set)
(nth (random (length set)) set))
How about just
public static <A> A getRandomElement(Collection<A> c, Random r) {
return new ArrayList<A>(c).get(r.nextInt(c.size()));
}
For fun I wrote a RandomHashSet based on rejection sampling. It's a bit hacky, since HashMap doesn't let us access it's table directly, but it should work just fine.
It doesn't use any extra memory, and lookup time is O(1) amortized. (Because java HashTable is dense).
class RandomHashSet<V> extends AbstractSet<V> {
private Map<Object,V> map = new HashMap<>();
public boolean add(V v) {
return map.put(new WrapKey<V>(v),v) == null;
}
#Override
public Iterator<V> iterator() {
return new Iterator<V>() {
RandKey key = new RandKey();
#Override public boolean hasNext() {
return true;
}
#Override public V next() {
while (true) {
key.next();
V v = map.get(key);
if (v != null)
return v;
}
}
#Override public void remove() {
throw new NotImplementedException();
}
};
}
#Override
public int size() {
return map.size();
}
static class WrapKey<V> {
private V v;
WrapKey(V v) {
this.v = v;
}
#Override public int hashCode() {
return v.hashCode();
}
#Override public boolean equals(Object o) {
if (o instanceof RandKey)
return true;
return v.equals(o);
}
}
static class RandKey {
private Random rand = new Random();
int key = rand.nextInt();
public void next() {
key = rand.nextInt();
}
#Override public int hashCode() {
return key;
}
#Override public boolean equals(Object o) {
return true;
}
}
}
The easiest with Java 8 is:
outbound.stream().skip(n % outbound.size()).findFirst().get()
where n is a random integer. Of course it is of less performance than that with the for(elem: Col)
With Guava we can do a little better than Khoth's answer:
public static E random(Set<E> set) {
int index = random.nextInt(set.size();
if (set instanceof ImmutableSet) {
// ImmutableSet.asList() is O(1), as is .get() on the returned list
return set.asList().get(index);
}
return Iterables.get(set, index);
}
In Mathematica:
a = {1, 2, 3, 4, 5}
a[[ ⌈ Length[a] Random[] ⌉ ]]
Or, in recent versions, simply:
RandomChoice[a]
Random[] generates a pseudorandom float between 0 and 1. This is multiplied by the length of the list and then the ceiling function is used to round up to the next integer. This index is then extracted from a.
Since hash table functionality is frequently done with rules in Mathematica, and rules are stored in lists, one might use:
a = {"Badger" -> 5, "Bird" -> 1, "Fox" -> 3, "Frog" -> 2, "Wolf" -> 4};
PHP, using MT:
$items_array = array("alpha", "bravo", "charlie");
$last_pos = count($items_array) - 1;
$random_pos = mt_rand(0, $last_pos);
$random_item = $items_array[$random_pos];
you can also transfer the set to array use array
it will probably work on small scale i see the for loop in the most voted answer is O(n) anyway
Object[] arr = set.toArray();
int v = (int) arr[rnd.nextInt(arr.length)];
If you really just want to pick "any" object from the Set, without any guarantees on the randomness, the easiest is taking the first returned by the iterator.
Set<Integer> s = ...
Iterator<Integer> it = s.iterator();
if(it.hasNext()){
Integer i = it.next();
// i is a "random" object from set
}
A generic solution using Khoth's answer as a starting point.
/**
* #param set a Set in which to look for a random element
* #param <T> generic type of the Set elements
* #return a random element in the Set or null if the set is empty
*/
public <T> T randomElement(Set<T> set) {
int size = set.size();
int item = random.nextInt(size);
int i = 0;
for (T obj : set) {
if (i == item) {
return obj;
}
i++;
}
return null;
}
Related
public class MyArrayList<T> implements MyList<T>{
int num; //number of things in the list
T[] vals; //to store the contents
#SuppressWarnings("unchecked")
public MyArrayList() {
num = 0;
vals = (T[]) new Object[3];
}
public T getUnique(){
T distinct = null;
int count = 0;
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){
count++;
}
if (count == 1){
return distinct;
}
}
}
if (distinct == null){
throw new IllegalArgumentException();
}
return distinct;
}
I am trying to work on a get Unique Method. A method getUnique that takes no arguments and returns the first value in the list that appears only once. (For example, calling the method on the list [1,2,3,1,2,4] would return 3 since 1 and
2 both appear more than once.) If the list is empty or all its values appear more than once, the method throws a NoSuchElementException
I have added some FIXME's to your code:
public T getUnique(){
T distinct = null;
int count = 0; // FIXME: move this initialization inside the i loop
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){ // FIXME: use .equals() not ==
count++;
}
if (count == 1){ // FIXME: move this check outside the j loop
return distinct;
}
}
}
if (distinct == null){ //FIXME: no check needed, just throw it
throw new IllegalArgumentException();
}
return distinct; //FIXME: no valid return can reach this point
}
Patrick Parker's advice will fix your code, but I wanted to provide a cleaner and faster solution to the problem of finding a unique element in a list. This algorithm runs in time O(n) instead of O(n^2).
public static <T> Optional<T> getUnique(List<T> ls) {
// Create a map whose keys are elements of the list and whose values are
// lists of their occurences. E.g. [1,2,3,1,2,4] becomes {1->[1, 1],
// 2->[2, 2], 3->[3], 4->[4]}. Then elements.get(x).size() tells us how
// many times x occured in ls.
Map<T, List<T>> elements = ls.stream()
.collect(Collectors.groupingBy(x -> x));
// Find the first element that occurs exactly one time in ls.
return ls.stream().filter(x -> elements.get(x).size() == 1)
.findFirst();
}
You might call it like this:
Integer[] vals = {1,2,3,1,2,4};
System.out.println(getUnique(Arrays.asList(vals))
.orElseThrow(NoSuchElementException::new));
This code uses Java 8 streams and Optional. Below is another implementation of the same algorithm that doesn't use Java 8 language features; if you've never encountered streams, you may find it more understandable.
private static <T> T getUnique(List<T> arr) {
Map<T, Integer> numOccurrences = new HashMap<>();
for (T item : arr) {
numOccurrences.put(item, 1 + numOccurrences.getOrDefault(item, 0));
}
for (T item : arr) {
if (numOccurrences.get(item) == 1) {
return item;
}
}
throw new NoSuchElementException();
}
I want to double a Stream (no DoubleStream). Meaning I start with a stream and want to get a new stream where each element of the old stream is streamed twice. So 1,2,3,4,4,5 gives us 1,1,2,2,3,3,4,4,4,4,5,5. Is there such a stream operation?
Create an inner stream which will contain current element two times and flatMap this stream.
stream.flatMap(e -> Stream.of(e,e))
If you want to multiply the number of elements by n you can create an utility method like this one:
public static <T> Stream<T> multiplyElements(Stream<T> in, int n) {
return in.flatMap(e -> IntStream.range(0, n).mapToObj(i -> e));
// we can also use IntStream.rangeClosed(1, n)
// but I am used to iterating from 0 to n (where n is excluded)
}
(but try to use a better name for this method, since the current one may be ambiguous)
Usage example:
multiplyElements(Stream.of(1,2), 3).forEach(System.out::println);
Output:
1
1
1
2
2
2
You can create a stream of 2 elements for each original element and flatMap it:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 5);
List<Integer> doubled = list.stream().flatMap(i -> Stream.of(i, i)).collect(toList());
Here's a simple example of what biziclop has described in the comments.
static <E> Collection<E> multiply(Collection<E> source, int count) {
return new AbstractCollection<E>() {
#Override
public int size() {
return count * source.size();
}
#Override
public Iterator<E> iterator() {
return new Iterator<E>() {
final Iterator<E> it = source.iterator();
E next;
int i = 0;
#Override
public boolean hasNext() {
return i < size();
}
#Override
public E next() {
if (hasNext()) {
if ((i % count) == 0) {
next = it.next();
}
++i;
return next;
} else {
throw new NoSuchElementException();
}
}
};
}
};
}
(Working example on Ideone.)
CW'd since it wasn't my idea and the flatMap suggestions more directly answer the question.
I have an ArrayList of Dico and I try to extract a distinct string from Arraylist of Dico.
This is the Dico class.
public class Dico implements Comparable {
private final String m_term;
private double m_weight;
private final int m_Id_doc;
public Dico(int Id_Doc, String Term, double tf_ief) {
this.m_Id_doc = Id_Doc;
this.m_term = Term;
this.m_weight = tf_ief;
}
public String getTerm() {
return this.m_term;
}
public double getWeight() {
return this.m_weight;
}
public void setWeight(double weight) {
this.m_weight = weight;
}
public int getDocId() {
return this.m_Id_doc;
}
}
I use this function to extract 1000 distinct value from middle of this array:
i start form the middle and i take only distinct value in both direction left and right
public static List <String> get_sinificativ_term(List<Dico> dico)
{
List <String> term = new ArrayList();
int pos_median= ( dico.size() / 2 );
int count=0;
int i=0;
int j=0;
String temp_d = dico.get(pos_median).getTerm();
String temp_g =temp_d;
term.add(temp_d);
while(count < 999) // count of element
{
if(!temp_d.equals(dico.get( ( pos_median + i) ).getTerm()))
{
temp_d = dico.get(( pos_median + i)).getTerm(); // save current term in temp
// System.out.println(temp_d);
term.add(temp_d); // add term to list
i++; // go to the next value-->right
count++;
// System.out.println(temp_d);
}
else
i++; // go to the next value-->right
if(!temp_g.equals(dico.get( ( pos_median+j ) ).getTerm()))
{
temp_g = dico.get(( pos_median+j )).getTerm();
term.add(temp_g );// add term to array
// System.out.println(temp_g);
j--; // go to the next value-->left
count++;
}
else
j--;// go to the next value-->left
}
return term;
}
I would like to make my solution more faster than this function,if is possible can i make this with Java SE 8 Streams ?
Streams will not make it faster but can make it much simpler and clearer.
Here's the simplest version. It will take all list indexes, sort them by distance to the middle of the list, get the corresponding term, filter out duplicates and limit to 1000 elements. It will certainly be slower than your iterative code, but much easier to follow because the code neatly mirrors its English description:
public static List<String> get_sinificativ_term(List<Dico> dicolist) {
int size = dicolist.size();
return IntStream.range(0, size)
.boxed()
.sorted(comparing(i -> Math.abs(size / 2 - i)))
.map(dicolist::get)
.map(Dico::getTerm)
.distinct()
.limit(1000)
.collect(toList());
}
If your list is really huge and you want to avoid sorting it, you can trade away some simplicity for performance. This version does a bit of math to go right-left-right-left from center:
public static List<String> get_sinificativ_term(List<Dico> dicolist) {
int size = dicolist.size();
return IntStream.range(0, size)
.map(i -> i % 2 == 0 ? (size + i) / 2 : (size - i - 1) / 2)
.mapToObj(i -> dicolist.get(i).getTerm())
.distinct()
.limit(1000)
.collect(toList());
}
Can't you do something like this?
public static List <String> get_sinificativ_term(List<Dico> dico) {
List<String> list = dico.stream()
.map(Dico::getTerm)
.distinct()
.limit(1000)
.collect(Collectors.toList());
if(list.size() != 1000) {
throw new IllegalStateException("Need at least 1000 distinct values");
}
return list;
}
You need to check the size because you can have less than 1000 distinct values. If efficiency is a concern you can try to run the pipeline in parallel and measure if its faster.
I'm trying to generalize the code to find all subsets of a given string(elements that are repeated will be treated as distinct) into one that would work for any list.
public class Subsets{
private static <T> void RecursiveSubsets(List<List<T>> list, ArrayList<T> soFar, List<T> rest)
{
if(rest.isEmpty())
{
list.add(soFar);
}
else
{
List<T> remaining;
if(rest.size() == 1)
{
remaining = new ArrayList<T>();
}
else
{
remaining = rest.subList(1, rest.size() - 1);
}
//include the element
ArrayList<T> includeFirst = new ArrayList<T>(soFar);
includeFirst.add(rest.get(0));
RecursiveSubsets(list, includeFirst, remaining);
//exclude the element
RecursiveSubsets(list, soFar, remaining);
}
}
public static <T> List<List<T>> getAllSubsets(List<T> set)
{
List<List<T>> subsets = new ArrayList<List<T>>();
RecursiveSubsets(subsets,new ArrayList<T>(),set);
return subsets;
}
public static void main(String [] args)
{
List<Integer> ints = new ArrayList<Integer>(){
{
add(0);add(1);add(2);add(3);
}
};
List<List<Integer>> allSubsets = getAllSubsets(ints);
System.out.println("Total Subsets returned : " + allSubsets.size());
for(int i=0; i<allSubsets.size(); ++i)
{
for(int j=0; j<allSubsets.get(i).size(); ++j)
{
System.out.print(allSubsets.get(i).get(j) + " ");
}
System.out.println();
}
}
}
After a few attempts I was able to get this to compile but this is what I get as output.
Even if I have more integers, it still returns this. I'm not able to figure out what I have missed and need help finding it.
$ java Subsets
Total Subsets returned : 4
0 1
0
1
Your program is actually almost correct, and you just have the sublist logic a bit wrong.
The javadoc for List.sublist says
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.
The word "exclusive" here is critical.
If you just change
remaining = rest.subList(1, rest.size() - 1);
to
remaining = rest.subList(1, rest.size());
your code works.
The logic of this (in pseudocode) is typically:
List<List<T>> subsets( List<T> list ){
if( list is empty ) return a list containing the empty list;
// else:
subsetsWithout = subsets( list w/o 0th element );
result.addAll(subsetsWithout);
for( subset in subsetsWithout )
result.add( subset + list[0] )
return result;
}
It looks like what you're doing is different, and the fact that you're trying to return things through the function parameters is making it more confusing.
I have to iterate through an arraylist in this manner.
ArrayList<Integer> li = new ArrayList<Integer>();
li.add(20);
li.add(30);
li.add(40);
li.add(50);
li.add(70);
for (int i = 0; i < li.size() - 1; i++)
System.out.println(li.get(i) + " " + li.get(i + 1));
Output:
20 30
30 40
40 50
50 70
How to do the same using an iterator?
Use two iterators. I tested this and it worked for me.
Iterator<Integer> first = li.listIterator();
// Will raise IndexOutOfBoundsException if list is empty.
Iterator<Integer> second = li.listIterator(1);
while (second.hasNext()) {
System.out.println(first.next() + " " + second.next());
}
Edit: No need for inner if. Silly me.
Explanation: the listIterator(index) method returns an iterator that starts at the specified position in the list where as listIterator() returns an iterator that starts at position zero.
The first iterator therefore starts at 0 and the second starts at 1. Then it is merely a question of printing the next() on both. This will work irrespective of whether the number of elements in the list is odd or even.
Edit 2
My logic fu is very weak today. Thanks #barjak for pointing out the case about the empty list and the unnecessary first.hasNext().
It's a bit more complicated:
Iterator<Integer> iter = li.iterator();
if (iter.hasNext()) {
for (int y = iter.next(), x; iter.hasNext(); y = x) {
x = iter.next();
System.out.println(y + " " + x);
}
}
or:
if (iter.hasNext()) {
for (int x = iter.next(); iter.hasNext();) {
System.out.println(x + " " + (x = iter.next()));
}
}
Slightly Modified Sagar V's solution to make it work. One iterator is enough to achieve this.
Iterator iter = li.iterator();
Integer int1 = null;
while (iter.hasNext()) {
if (int1 == null) {
int1 = (Integer) iter.next();
}
System.out.print(int1 + " ");
if (iter.hasNext()) {
Integer int2 = (Integer) iter.next();
System.out.println(int2);
int1 = int2;
} else {
break;
}
}
}
There are many solutions, that can be appropriate depending on your needs.
Solution 1 : fixed-size view
The classical way to iterate on a subset of a list is to create a narrower view of the original list, and to iterate on this whole view. The subList method is used to create such a view.
List<Integer> l = // initialization code
int limitIndex = Math.max(l.size()-1, 0); // needed for empty list
for (int v : l.subList(0, limitIndex)) {
// your code
}
Note that I used a 'foreach' loop, which is a convenient way to use iterators. This is strictly equivalent to this code :
Iterator<Integer> it = l.subList(0, limitIndex).iterator();
while(it.hasNext()) {
int v = it.next();
// your code
}
Also, note that the subList method does not create a new list : it only creates a 'view' on the original list. The content of the original list is not copied, and all changes made to the original list are visible from the list created by subList.
Solution 2 : a custom Iterator/Iterable
If all you need is an iterator that always iterates from 0 to n-1, you can define a new Iterable tailored to that particular need.
public class NoLastIterable<T> implements Iterable<T> {
private final List<T> backend;
public NoLastIterable(List<T> backend) {
this.backend = backend;
}
public Iterator<T> iterator() {
return new Iterator<T>() {
private int nextIndex;
public boolean hasNext() {
return nextIndex < backend.size() -1;
}
public T next() {
return backend.get(nextIndex++);
}
public void remove() {
throw new UnsupportedOperationException("not implemented");
}
};
}
}
This class is used like this :
for (int v : new NoLastIterable<Integer>(l)) {
// your code
}
Solution 3
You can even create your custom view of a List, just like subList does, but with more flexibility.
public class NoLastList<T> extends AbstractList<T> {
private final List<T> backend;
public NoLastList(List<T> backend) {
this.backend = backend;
}
#Override
public T get(int index) {
if (index >= size()) {
throw new IndexOutOfBoundsException();
}
return backend.get(index);
}
#Override
public int size() {
return Math.max(0, backend.size()-1);
}
}
Same usage as the other solutions :
for (int v : new NoLastList<Integer>(l)) {
// your code
}
The benefits of this solution can be seen in the following situation :
the original list is created and initialized
the NoLastList instance is created (as a view of the original List)
some elements are added to the original list
In this situation, iterating over NoLastList will take into account the elements that were added lately. NoLastList always represents a view of the elements from 0 to n-1, even if n (the size) changes.