By flat tree I mean a table where each child has a link to its parent. Also tree have to be limited by depth and size (max number of nodes). When object and parent ids are equal it's one of the root nodes. So want to generate data structure like this:
id | parent id
1 | 1
2 | 2
3 | 2
4 | 1
I've solved this task, but resulting code somewhat cumbersome:
private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
public static <I, T extends Node<I>> List<T> generateTree(int count,
int maxDepth,
Supplier<T> supplier) {
List<T> result = new ArrayList<>(count);
int remainingDepth = maxDepth;
while (remainingDepth > 0 && result.size() < count) {
final boolean firstStep = result.isEmpty();
final boolean lastStep = remainingDepth == 1;
final int remainingCount = count - result.size();
final int generatedCount = !lastStep ?
RANDOM.nextInt(1, remainingCount + 1) :
remainingCount;
List<T> generatedNodes = IntStream.range(0, generatedCount).boxed()
.map(i -> {
T value = supplier.get();
value.parentId = firstStep ?
value.id : // root node, id = parent id
result.get(RANDOM.nextInt(0, result.size())).id; // child node, find random parent
return value;
})
.collect(Collectors.toList());
result.addAll(generatedNodes);
remainingDepth--;
}
return result;
}
static class Node<I> {
public I id;
public I parentId;
public Node(I id) {
this.id = id;
}
#Override
public String toString() {
return id + " | " + parentId;
}
}
#Test
public void test() {
List<Node<Integer>> result = generateTree(100, 4, () -> new Node<>(RANDOM.nextInt(100, 1000)));
result.forEach(System.out::println);
}
Yeah, it can be simplified by remove a couple of unnecessary variables, those just improve readability, but in general I don't see ways to improve the most complex part - obtaining random parent id.
So I wonder is it possible to rewrite this implementation to Stream API (I mean reducers, of course). Will it be simpler? I've tried to do so but functional paradigm just blows my brain. Could someone please help me?
I don’t see a way to rewrite the assignment of parent IDs using the Stream API to simpler code.
Instead, separate the two different concerns of the code 1) generate count Node objects and 2) assign them parent IDs.
public static <I, T extends Node<I>>
List<T> generateTree(int count, int maxDepth, Supplier<T> supplier) {
ThreadLocalRandom r = ThreadLocalRandom.current();
List<T> result = IntStream.range(0, count)
.mapToObj(i -> supplier.get())
.collect(Collectors.toList());
for(int index = 0, level = 0, numItemsInThisLevel;
level < maxDepth && index < count; level++, index += numItemsInThisLevel) {
int remaining = count - index;
numItemsInThisLevel = level < maxDepth - 1? r.nextInt(remaining) + 1: remaining;
for(T value: result.subList(index, index + numItemsInThisLevel))
value.parentId = index == 0? value.id: result.get(r.nextInt(0, index)).id;
}
return result;
}
Generating count objects is straight-forward and should not need further explanation. Your algorithm, as far as I understood, iterates over up to maxDepth ranges of the objects and assigns them parent IDs taken from the IDs of random objects before that range. I wrote this as a loop over ranges reflecting exactly that. Note that it would be easy to adapt this to use only IDs from the previous level, to get the specified depth exactly.
One important note: ThreadLocalRandom is, as the name suggests, local to the thread and should always get acquired via current() by the using thread. So storing it in a static final variable means, only the thread that executed the class initializer would be allowed to use that instance. On the other hand, current() is cheap, there would be no advantage in caching the result anyway.
Ok, I've figured out better solution. It's a custom Collector. Also, it's easier to track depth when it's just one of node properties, which can easily done via wrapper. Here's an example:
static class Node<I> {
public I id;
public I parentId;
public int depth;
public Node(I id) {
this.id = id;
this.parentId = id;
}
#Override
public String toString() {
return id + " | " + parentId + " | depth: " + depth;
}
}
public static <I, T extends Node<I>> List<T> generateTreeStream(int count,
int maxDepth,
Supplier<T> supplier) {
Collector<T, List<T>, List<T>> collector = Collector.of(
ArrayList::new,
(list, node) -> {
if (!list.isEmpty()) {
int random = ThreadLocalRandom.current().nextInt(0, list.size());
T parent = list.get(random);
if (parent.depth < maxDepth) {
node.parentId = parent.id;
node.depth = parent.depth + 1;
}
}
list.add(node);
},
(left, right) -> {
left.addAll(right);
return left;
}
);
return IntStream.range(0, count)
.mapToObj(i -> supplier.get())
.collect(collector);
}
Related
I have a method that sorts a List by different criteria and returns the name (an instance variable) of the one with maximum value. In case more than one instance is having the maximum, all of their names should be concatenated.
Let's say I have Class A as follows.
Class A {
...
String getName(){...}
int getValue1() {...}
int getValue2() {...}
...
int getValueN() {...}
...
}
I have a List<A> listToSort. I would normally sort this list as listToSort.sort(Comparator.comparing(A::getValue1)) or listToSort.sort(Comparator.comparing(A::getValue2)), so on and so forth. Then get the ones sharing the maximum value.
In a method I believe this should be done as:
String getMaxString (Comparator c) {
listToSort.sort(c);
...
}
and send Comparator.comparing(A.getValueX) as parameter to call it with different methods. (X here indicates an arbitrary number for the getValue function).
However, I need to also return other instances sharing the same values
I will need to pass the Class methods to my method and call on instances as:
String getMaxString (Comparator c) {
listToSort.sort(c);
int maxValue = listToSort.get(listToSort.size() - 1).getValueX();
String maxString = listToSort.get(listToSort.size() - 1).getName();
for (int i = listToSort.size() - 2; i >= 0; i--) {
if (listToSort.get(i).getValueX()() == maxValue) {
maxString += ", " + listToSort.get(i).getName();
}
}
return maxString;
}
How would I pass this method to call on instances here? Or do I need to consider another way?
Edit:
I have a list of Courses as List<Course> mylist where a course can be simplified as:
Class Course {
private String name;
private int capacity;
private int students;
...
//bunch of getters.
}
My task is to return Strings for the course(es) with maximum capacity, the course(es) with maximum registered students, the course(es) with most difficulty, the maximum filled percentage, the course(es) with the maximum number of TAs etc...
Edit 2:
As requested in the comment section.
List of
Course a (name "a", capacity 10, students 5)
Course b (name "b", capacity 20, students 5)
Course c (name "c", capacity 30, students 0)
Sorting based on capacity should return "c"
Sorting based on students should return "a b"
You can pass the getter method and create the Comparator in getMaxString:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
public class Foo {
static class AClass {
private final String name;
private final int value1;
private final int value2;
String getName() { return name; }
int getValue1() { return value1; }
int getValue2() { return value2; }
public AClass(String name, int value1, int value2) {
this.name = name;
this.value1 = value1;
this.value2 = value2;
}
}
static String getMaxString(Function<AClass,Integer> f, List<AClass> listToSort) {
listToSort.sort(Comparator.comparing(f));
int maxValue = f.apply(listToSort.get(listToSort.size() - 1));
String maxString = listToSort.get(listToSort.size() - 1).getName();
for (int i = listToSort.size() - 2; i >= 0; i--) {
if (f.apply(listToSort.get(i)) == maxValue) {
maxString += ", " + listToSort.get(i).getName();
}
}
return maxString;
}
public static void main(String[] args) {
List<AClass> list = new ArrayList<>();
list.add(new AClass("a", 1,2));
list.add(new AClass("b", 1,2));
list.add(new AClass("c", 2,1));
list.add(new AClass("d", 2,1));
System.out.println(getMaxString(AClass::getValue1, list));
System.out.println(getMaxString(AClass::getValue2, list));
}
}
As Tim Moore suggested above, it isn't necessary to sort the list (which has cost O(n*log n)), we can traverse it twice:
static String getMaxString2(ToIntFunction<AClass> f, List<AClass> listToSort) {
int maxValue = listToSort.stream().mapToInt(f).max().orElseThrow();
return listToSort.stream()
.filter(a -> maxValue == f.applyAsInt(a))
.map(AClass::getName)
.collect(Collectors.joining(", "));
}
Note that you should test your code with an empty list.
It's useful to look at the type signature for Comparator.comparing, because it sounds like you want to do something similar:
static <T,U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor)
The interesting part is the type of keyExtractor. Roughly speaking, it's a function from the type of the object you're comparing, to the type of the field you want to use for the comparison. In our case, these correspond to the A class and Integer. Because these types are fixed in this example, you can declare a method with a signature like this:
String getMaxString(Function<A, Integer> property)
With the existing algorithm, it can be used this way:
String getMaxString(Function<A, Integer> property) {
listToSort.sort(Comparator.comparing(property));
int maxValue = property.apply(listToSort.get(listToSort.size() - 1));
String maxString = listToSort.get(listToSort.size() - 1).getName();
for (int i = listToSort.size() - 2; i >= 0; i--) {
if (listToSort.get(i).getValueN() == maxValue) {
maxString += ", " + listToSort.get(i).getName();
}
}
return maxString;
}
However, it isn't necessary or efficient to sort the entire list in order to determine the maximum elements, as this can be determined by iterating through the list once:
String getMaxString(Function<A, Integer> property) {
int maxValue = Integer.MIN_VALUE;
StringBuilder maxString = new StringBuilder();
for (A element : listToSort) {
int currentValue = property.apply(element);
if (currentValue > maxValue) {
// there is a new maximum, so start the string again
maxString = new StringBuilder(element.getName());
maxValue = currentValue;
} else if (currentValue == maxValue) {
// equal to the existing maximum, append it to the string
if (maxString.length() > 0) {
maxString.append(", ");
}
maxString.append(element.getName());
}
// otherwise, it's less than the existing maximum and can be ignored
}
return maxString.toString();
}
Either way, you can call it using the same method reference syntax:
getMaxString(A::getValueN)
Time complexity O(n) - only one iteration through the dataset.
Hope it'll help.
If something will be unclear fill free to raise a question.
Main
public class MaxClient {
public static void main(String[] args) {
Comparator<A> comp = Comparator.comparingInt(A::getVal1);
List<A> items = List.of(new A(1, 8), new A(2, 8), new A(5, 8), new A(5, 27), new A(3, 8));
items.stream()
.collect(new GetMax(comp))
.forEach(System.out::println);
}
}
Custom collector GetMax
public class GetMax implements Collector <A, Deque<A>, Deque<A>> {
private final Comparator<A> comp;
public GetMax(Comparator<A> comp) {
this.comp = comp;
}
#Override
public Supplier<Deque<A>> supplier() {
return ArrayDeque::new;
}
#Override
public BiConsumer<Deque<A>, A> accumulator() {
return (stack, next) -> {
if (!stack.isEmpty() && comp.compare(next, stack.peekFirst()) > 0) stack.clear();
if (stack.isEmpty() || comp.compare(next, stack.peekFirst()) == 0) stack.offerLast(next);
};
}
#Override
public BinaryOperator<Deque<A>> combiner() {
return (stack1, stack2) -> {
if (stack1.isEmpty()) return stack2;
if (stack2.isEmpty()) return stack1;
if (comp.compare(stack1.peekFirst(), stack2.peekFirst()) == 0) {
stack1.addAll(stack2);
}
return stack1;
};
}
#Override
public Function<Deque<A>, Deque<A>> finisher() {
return stack -> stack;
}
#Override
public Set<Characteristics> characteristics() {
return Set.of(Characteristics.UNORDERED);
}
}
Class A that I used for testing purposes
public class A {
private int val1;
private int val2;
public A(int val1, int val2) {
this.val1 = val1;
this.val2 = val2;
}
public int getVal1() {
return val1;
}
public int getVal2() {
return val2;
}
#Override
public String toString() {
return "A val1: " + val1 + " val2: " + val2;
}
}
OUTPUT
A val1: 5 val2: 8
A val1: 5 val2: 27
Thanks for posting the information I requested. Here is what I came up with.
Create a list of Course objects
List<Course> list = List.of(
new Course("a", 10, 5),
new Course("b", 20, 5),
new Course("c", 30, 0));
Stream the methods and apply them to the list
List<String> results = Stream.<Function<Course, Integer>>of(
Course::getCapacity,
Course::getStudents)
.map(fnc-> getMaxString(fnc, list))
.toList();
results.forEach(System.out::println);
print the results
c
a b
I wrote a simple method that takes a method reference and list and finds the maximum. It does not do any sorting.
allocate a list to hold the names
set the maximum to the lowest possible
iterate thru the list applying the method.
if the value is greater than the current max replace it and clear the current list of names.
otherwise, if equal, add a new name.
once done, return the formatted string.
static String getMaxString(Function<Course, Integer> fnc,
List<Course> list) {
List<String> result = new ArrayList<>();
int max = Integer.MIN_VALUE;
for (Course obj : list) {
int val = fnc.apply(obj);
if (val >= max) {
if (val > max) {
result.clear();
}
max = val;
result.add(obj.getName());
}
}
return String.join(" ", result);
}
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;
}
I want to get a min or max item from a list according to some condition.
The snippet bellow summarizes what I doing:
Optional<Person> target;
if(condition){
target = detailedList.stream().min((d1, d2) -> d1.age() + d2.age());
} else {
target = detailedList.stream().max((d1, d2) -> d1.age() + d2.age());
}
It works but is quite verbose. In essence I want to select either the method min or max in the stream. Is there a better way to do this?
Here's another way:
Comparator<Person> comp = Comparator.comparingInt(Person::age);
BinaryOperator<Person> op
= condition ? BinaryOperator.minBy(comp) : BinaryOperator.maxBy(comp);
Optional<Person> target = list.stream().reduce(op);
I would suggest the method that makes your intent clearest is:
Comparator<Person> ageComparator = Comparator.comparingInt(Person::age);
Optional<Person> target = condition ?
list.stream().min(ageComparator) : list.stream().max(ageComparator);
You could do this:
Comparator<Person> c = Comparator.comparingInt(Person::age);
Optional<Person> target = detailedList.stream().min(condition ? c : c.reversed());
It's shorter, but personally I think combining min with reversed to find the maximum is a bit of a hack. I would stick to the original.
Another solution would be to calculate both the min and the max with the same collecting step. For that, we can inspire ourselves from the IntSummaryStatistics class and construct a ObjectSummaryStatistics which would hold the min and max values.
This solution is probably too much for your particular use-case. It might be handy only if you find yourself doing this a lot.
The min and max are initialized to null and are updated each time an element is accepted or a combine is made. I used Optionals as return value to be consistent with what the API returns for the common min and max operations.
public class ObjectSummaryStatistics<T> implements Consumer<T> {
private long count;
private T min;
private T max;
private Comparator<T> comparator;
public ObjectSummaryStatistics(Comparator<T> comparator) {
this.comparator = Objects.requireNonNull(comparator, "A comparator must be set");
}
#Override
public void accept(T t) {
min = count == 0 ? t : min(min, t);
max = count == 0 ? t : max(max, t);
count++;
}
public void combine(ObjectSummaryStatistics<T> other) {
if (other.comparator != comparator) {
throw new IllegalArgumentException("Can't combine with a summary statistics having a different comparator");
}
if (count == 0) {
min = other.min;
max = other.max;
} else if (other.count > 0) {
min = min(min, other.min);
max = max(max, other.max);
}
count += other.count;
}
public Optional<T> getMin() {
return Optional.ofNullable(min);
}
public Optional<T> getMax() {
return Optional.ofNullable(max);
}
public long getCount() {
return count;
}
private T min(T t1, T t2) {
return comparator.compare(t1, t2) <= 0 ? t1 : t2;
}
private T max(T t1, T t2) {
return comparator.compare(t1, t2) >= 0 ? t1 : t2;
}
}
Then you could construct a Collector that would collect to this class:
public static <T> Collector<T, ?, ObjectSummaryStatistics<T>> summarizing(Comparator<T> comparator) {
return Collector.of(
() -> new ObjectSummaryStatistics<T>(comparator),
ObjectSummaryStatistics::accept,
(s1, s2) -> { s1.combine(s2); return s1; }
);
}
Finally, your code becomes:
ObjectSummaryStatistics<Person> s = detailedList.stream().collect(summarizing((d1, d2) -> d1.age() + d2.age()));
System.out.println(s.getMin());
System.out.println(s.getMax());
Side-note: the Comparator you have in your question is not transitive so it won't work as-is
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.
Looking at the following class I've made:
public class FibonacciSupplier implements Iterator<Integer> {
private final IntPredicate hasNextPredicate;
private int beforePrevious = 0;
private int previous = 1;
private FibonacciSupplier(final IntPredicate hasNextPredicate) {
this.hasNextPredicate = hasNextPredicate;
}
#Override
public boolean hasNext() {
return hasNextPredicate.test(previous);
}
#Override
public Integer next() {
int result = beforePrevious + previous;
beforePrevious = previous;
previous = result;
return result;
}
public static FibonacciSupplier infinite() {
return new FibonacciSupplier(i -> true);
}
public static FibonacciSupplier finite(final IntPredicate predicate) {
return new FibonacciSupplier(predicate);
}
}
And the usage of it in:
public class Problem2 extends Problem<Integer> {
#Override
public void run() {
result = toList(FibonacciSupplier.finite(i -> (i <= 4_000_000)))
.stream()
.filter(i -> (i % 2 == 0))
.mapToInt(i -> i)
.sum();
}
#Override
public String getName() {
return "Problem 2";
}
private static <E> List<E> toList(final Iterator<E> iterator) {
List<E> list = new ArrayList<>();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return list;
}
}
How would I be able to create an infinite Stream<E>?
If I were to use Stream<Integer> infiniteStream = toList(FibonacciSupplier.infinite()).stream(), I would, possibly surprisingly, never get an infinite stream.
Instead the code would loop forever in the creation of the list in an underlying method.
This so far is purely theoretical, but I can definately understand the need for it if I would want to first skip the first x numbers from an infinite stream, and then limit it by the last y numbers, something like:
int x = MAGIC_NUMBER_X;
int y = MAGIC_NUMBER_y;
int sum = toList(FibonacciSupplier.infinite())
.stream()
.skip(x)
.limit(y)
.mapToInt(i -> i)
.sum();
The code would not ever return a result, how should it be done?
Your mistake is to think that you need an Iterator or a Collection to create a Stream. For creating an infinite stream, a single method providing one value after another is enough. So for your class FibonacciSupplier the simplest use is:
IntStream s=IntStream.generate(FibonacciSupplier.infinite()::next);
or, if you prefer boxed values:
Stream<Integer> s=Stream.generate(FibonacciSupplier.infinite()::next);
Note that in this case the method does not have to be named next nor fulfill the Iterator interface. But it doesn’t matter if it does as with your class. Further, as we just told the stream to use the next method as a Supplier, the hasNext method will never be called. It’s just infinite.
Creating a finite stream using your Iterator is a bit more complicated:
Stream<Integer> s=StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
FibonacciSupplier.finite(intPredicate), Spliterator.ORDERED),
false);
In this case if you want a finite IntStream with unboxed int values your FibonacciSupplier should implement PrimitiveIterator.OfInt.
In Java 8 there are no public, concrete classes implementing the interface Stream. However, there are some static factory methods. One of the most important is StreamSupport.stream. In particular, it is used in the default method Collection.stream –inherited by most collection classes:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
The default implementation of this method creates a Spliterator by invoking spliterator(), and passes the created object to the factory method. Spliterator is a new interface introduced with Java 8 to support parallel streams. It is similar to Iterator, but in contrast to the latter, a Spliterator can be divided into parts, that can be processed independently. See Spliterator.trySplit for details.
The default method Iterable.spliterator was also added in Java 8, so that every Iterable class automatically supports Spliterators. The implementation looks as follows:
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
The method creates the Spliterator from an arbitrary Iterator. If you combine these two steps, you can create a Stream from an arbitrary Iterator:
<T> Stream<T> stream(Iterator<T> iterator) {
Spliterator<T> spliterator
= Spliterators.spliteratorUnknownSize(iterator, 0);
return StreamSupport.stream(spliterator, false);
}
To get an impression of Spliterators, here is a very simple example without using collections. The following class implements Spliterator to iterate over a half-open interval of integers:
public final class IntRange implements Spliterator.OfInt {
private int first, last;
public IntRange(int first, int last) {
this.first = first;
this.last = last;
}
public boolean tryAdvance(IntConsumer action) {
if (first < last) {
action.accept(first++);
return true;
} else {
return false;
}
}
public OfInt trySplit() {
int size = last - first;
if (size >= 10) {
int temp = first;
first += size / 2;
return new IntRange(temp, first);
} else {
return null;
}
}
public long estimateSize() {
return Math.max(last - first, 0);
}
public int characteristics() {
return ORDERED | DISTINCT | SIZED | NONNULL
| IMMUTABLE | CONCURRENT | SUBSIZED;
}
}
You can use the low level stream support primitives and the Spliterators library to make a stream out of an Iterator.
The last parameter to StreamSupport.stream() says that the stream is not parallel. Be sure to let it like that because your Fibonacci iterator depends on previous iterations.
return StreamSupport.stream( Spliterators.spliteratorUnknownSize( new Iterator<Node>()
{
#Override
public boolean hasNext()
{
// to implement
return ...;
}
#Override
public ContentVersion next()
{
// to implement
return ...;
}
}, Spliterator.ORDERED ), false );
To add another answer, perhaps AbstractSpliterator is a better choice, especially given the example code. Generate is inflexible as there is no [good] way to give a stop condition except by using limit. Limit only accepts a number of items rather than a predicate, so we have to know how many items we want to generate - which might not be possible, and what if the generator is a black box passed to us?
AbstractSpliterator is a halfway house between having to write a whole spliterator, and using Iterator/Iterable. AbstractSpliterator lacks just the tryAdvance method where we first check our predicate for being done, and if not pass the generated value to an action. Here's an example of a Fibonacci sequence using AbstractIntSpliterator:
public class Fibonacci {
private static class FibonacciGenerator extends Spliterators.AbstractIntSpliterator
{
private IntPredicate hasNextPredicate;
private int beforePrevious = 0;
private int previous = 0;
protected FibonacciGenerator(IntPredicate hasNextPredicate)
{
super(Long.MAX_VALUE, 0);
this.hasNextPredicate = hasNextPredicate;
}
#Override
public boolean tryAdvance(IntConsumer action)
{
if (action == null)
{
throw new NullPointerException();
}
int next = Math.max(1, beforePrevious + previous);
beforePrevious = previous;
previous = next;
if (!hasNextPredicate.test(next))
{
return false;
}
action.accept(next);
return true;
}
#Override
public boolean tryAdvance(Consumer<? super Integer> action)
{
if (action == null)
{
throw new NullPointerException();
}
int next = Math.max(1, beforePrevious + previous);
beforePrevious = previous;
previous = next;
if (!hasNextPredicate.test(next))
{
return false;
}
action.accept(next);
return true;
}
}
public static void main(String args[])
{
Stream<Integer> infiniteStream = StreamSupport.stream(
new FibonacciGenerator(i -> true), false);
Stream<Integer> finiteStream = StreamSupport.stream(
new FibonacciGenerator(i -> i < 100), false);
// Print with a side-effect for the demo
infiniteStream.limit(10).forEach(System.out::println);
finiteStream.forEach(System.out::println);
}
}
For more details I've covered generators in Java 8 in my blog http://thecannycoder.wordpress.com/