How to get nth element of a Set - java

More specifically: how to get the nth element of a LinkedHashSet (which has a predictable iteration order)? I want to retrieve the nth element inserted into this Set (which wasn't already present).
Is it better to use a List:
List<T> list = new ArrayList<T>(mySet);
T value = list.get(x); // x < mySet.size()
or the toArray(T [] a) method:
T [] array = mySet.toArray(new T[mySet.size()]);
T value = array[y]; // y < mySet.size()
Other than the (likely slight) performance differences, anything to watch out for? Any clear winner?
Edit 1
NB: It doesn't matter why I want the last-inserted element, all that matters is that I want it. LinkedHashSet was specifically chosen because it "defines the iteration ordering, which is the order in which elements were inserted into the set (insertion-order). Note that insertion order is not affected if an element is re-inserted into the set."
Edit 2
This question seems to have devolved into a discussion of whether any Set implementation can ever preserve original insertion order. So I put up some simple test code at http://pastebin.com/KZJ3ETx9 to show that yes, LinkedHashSet does indeed preserve insertion order (the same as its iteration order) as its Javadoc claims.
Edit 3
Modified the description of the problem so that everybody isn't too focused on retrieving the last element of the Set (I originally thought that the title of the question would be enough of a hint — obviously I was wrong).

This method is based on the updated requirement to return the nth element, rather than just the last element. If the source is e.g. a Set with identifier mySet, the last element can be selected by nthElement(mySet, mySet.size()-1).
If n is small compared to the size of the Set, this method may be faster than e.g. converting to an ArrayList.
/**
* Return an element selected by position in iteration order.
* #param data The source from which an element is to be selected
* #param n The index of the required element. If it is not in the
* range of elements of the iterable, the method returns null.
* #return The selected element.
*/
public static final <T> T nthElement(Iterable<T> data, int n){
int index = 0;
for(T element : data){
if(index == n){
return element;
}
index++;
}
return null;
}

I'd use the iterator of the LinkedHashSet if you want to retrieve the last element:
Iterator<T> it = linkedHashSet.iterator();
T value = null;
while (it.hasNext()) {
value = it.next();
}
After the loop execution value will be referring to the last element.

So I decided to go with a slight variation of the answer by #Juvanis.
To get at the nth element in a LinkedHashSet:
Iterator<T> itr = mySet.iterator();
int nth = y;
T value = null;
for(int i = 0; itr.hasNext(); i++) {
value = itr.next();
if (i == nth) {
break;
}
}
Version 2 of the code:
public class SetUtil {
#Nullable
public static <T> T nthElement(Set<T> set, int n) {
if (null != set && n >= 0 && n < set.size()) {
int count = 0;
for (T element : set) {
if (n == count)
return element;
count++;
}
}
return null;
}
}
NB: with some slight modifications the method above can be used for all Iterables<T>.
This avoids the overhead of ensuring that a Set and a List stay in sync, and also avoids having to create a new List every time (which will be more time-consuming than any amount of algorithmic complexity).
Obviously I am using a Set to ensure uniqueness and I'd rather avoid a lengthy explanation as to why I need indexed access.

You can go with below solution,
here i have added object of ModelClass in HashSet.
ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
m1 = (ModelClass) itr.next();
if(nth == index) {
System.out.println(m1);
break;
}
}

Set is unordered so the information on the last element inserted is lost. You cannot as such get the last element inserted. So don't use Set in the first place, or, if you really want to keep track of the last element, create a class containing that like this
class mySetAndLast extends Set{
T last;
Set<T> mySet;
}
now the question is what is the 'last element inserted'. Imagine your set was empty
-> insert x -> ok, x is the last inserted
-> insert y (y!=x) -> ok: y is the last inserted
-> insert x -> ?
is now x or y the last inserted?
x does not get inserted because y was the last element inserted and x already is an element of the set, on the other hand x from the user's point of view was the last inserted..

For your own, internal purpose, you could "hack" your own Set from any List implementation:
public class ListSet<E> extends ArrayList<E> implements Set<E> {
#Override
public boolean add(E item) {
return contains(item) ? false : super.add(item);
}
// ... and same for add(int, E), addAll(...), etc.
}
That example is slow (O(n) for an add) but, as you are the one implementing it, you can go back to it with smarter code for contains() based on your specifications.

Related

Java with ArrayLists the index of function

is there a way with the index of function to return the index of a value that is part of a class like just one field of the bigger structure.. I got a simple contact class and I want to return the index when the id is a certain value .. should I be using a different structure than an arrayList it is doing most of what I want but the index of function is frustrating
I think the easiest way is to just iterate over the array, and check the condition with "if". That will be O(n).
You can use the Predicate method explained here.
Optional<Integer> indexOfMatch = IntStream.range(0, yourList.size())
.filter(i -> valueYouAreLookingFor.equals(yourList.get(i).getFieldYouAreChecking()))
.findFirst();
Or if the field holds a primitive value:
Optional<Integer> indexOfMatch = IntStream.range(0, yourList.size())
.filter(i -> valueYouAreLookingFor == yourList.get(i).getFieldYouAreChecking())
.findFirst();
If there is an element in the list that matches your predicate, indexOfMatch will have the index of that element. If not, indexOfMatch will be an empty Optional.
Regarding whether an ArrayList is the appropriate structure, generally if you are working with a list of values, an implementation of List is what you want. Whether it should be ArrayList or some other implementation depends on details of what you are doing with the list. For small list sizes, it often doesn't really matter which implementation you use.
well I switched to a vector from an array list but it did not really help but I did use a loop and the list size and just put the contact in a container each time so I could do my comparison it was kinda messy but I got the index that way.
static int SearchForContact(String ContactID) {
int temp = -1;
Contact searchCon;
for (int z = 0 ; z < contactVector.size(); z++)
{searchCon = contactVector.get(z);
if(searchCon.getId() == ContactID)
{temp = z;}
}
if (temp == -1) {
throw new IllegalArgumentException("Contact not found");
}
return temp;
}
I am iterating over the ArrayList and seeing whether the current value is the id value you want.
int yourValue = 25; //I am assuming it to be an int of value 25, you can keep it whatever you want.
for (int i = 0; i < yourArrayList.size(); i++)
{
if (yourArrayList.get(i) == yourValue)
{
return i; //returning the index value
}
}
return null; //this will run if the value doesn't exist.
Obviously, this would need to be inside a method that returns an integer that is the index. Above, yourArrayList is the ArrayList you are using, and yourValue is the value you need to find. It doesn't have to be an int.

Adding Element to Middle of an Array (Data Structures)

I'm having trouble implementing an add method to an array structure for my data structures class and am not able to find a way to wrap my head around how to do this correctly. I am aware this is an impractical way handling data, but hey data structures.
Instructions:
The add method ensures that this set contains the specified element.
Neither duplicates nor null values are allowed. The method returns
true if this set was modified (i.e., the element was added) and false
otherwise. If the array is full, you must “resize” to an array twice
as large. Note that the constraint on the generic type parameter T of
the ArraySet class ensures that there is a natural order on the values
stored in an ArraySet. You must maintain the internal array in
ascending natural order at all times. The time complexity of the add
method must be O ( N ), where N is the number of elements in the set.
We are able to use the Array and Iterator classes only! Please do not give an answer using arraylists.
My Psudocode is:
Check element exists, check if array is full, if full double size,
compare elements to find an index where we can maintain natural order
and insert element or find the duplicate and exit, copy array from
top down and combine with inserted element and bottom part.
Actual Code:
//Given Fields
T[] elements;
int size;
//Add Method
public boolean add(T element) {
if (element != null) {
int index = -1;
int last_compare = -1;
for (int i = 0; i < size; i++) {
int compare = elements[i].compareTo(element);
if (compare > 0 && last_compare < 0) { //larger element, last element was smaller.
if (isFull()) {
resize(elements.length * 2);
}
index = i;
break;
} else if (compare == 0) {
return false;
}
last_compare = compare;
}
T[] temp = null;
//Need to copy the array here
} else {
return false;
}
}
I don't know how to insert this correctly while maintaining O(N) time complexity.
Any ideas?

If only one element in a hashset, how can I get it out?

I have a set like below:
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
How can I get the 1 out? I can do it by for(integer i : set). My specified problem is "Given an array of integers, every element appears twice except for one. Find that single one."
I want to use add elements into the set if the set doesn't contain it and remove existing elements during the loop. And the last remaining element is the answer. I don't know how to return it.
public static int singleNumber(int[] A) {
HashSet<Integer> set = new HashSet<>();
for (int a : A) {
if (!set.contains(a)) {
set.add(a);
} else {
set.remove(a);
}
}
/**
* for(Integer i : set) { return i; }
*return A[0]; //need one useless return
/**
* while(set.iterator().hasNext()) { return set.iterator().next(); }
* return A[0]; //need one useless return
*/
return set.toArray(new Integer[1])[0];
}
set.iterator().next()
Do so only if you are sure there is an element in the set. Otherwise next() will throw an exception.
Simply try using HashSet#toArray() method
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
if (set.size() == 1) { // make sure that there is only one element in set
Integer value = set.toArray(new Integer[1])[0];
System.out.println(value);//output 1
}
The typical solution includes a check if the current iterator position has any left element through setIterator.hasNext() which returns true only if there is an extra element unchecked. For example
HashSet set = new HashSet();
Iterator setIterator = set.iterator();
while(setIterator.hasNext()){
String item = setIterator().next();
...
}
If you know what the element is and you just want to empty the set, you can use remove(Object o) (or clear() for that matter). If you don't know what it is and want to see it without removing it, use an iterator. If you don't know what it is and want to remove it, you should use an iterator using the iterator's remove() method. This is the safe (and recommended) way to remove elements from a collection. Since Set is unordered, it's difficult to specify what you want to remove. And for any collection, you would usually only know what you are removing if you iterate through the collection.
Solution Using Java Stream
If you want to use Java Stream any of the following options will give you the desired result:
Option 1
Just return the only element from the stream:
set.stream().findFirst().get()
Option 2
Or use Stream.reduce; since adding the only element to zero has no effect
(a little too much IMHO :))
set.stream().reduce(0, Integer::sum)
You can test it here.

Inserting into Sorted LinkedList Java

I have this code below where I am inserting a new integer into a sorted LinkedList of ints but I do not think it is the "correct" way of doing things as I know there are singly linkedlist with pointer to the next value and doubly linkedlist with pointers to the next and previous value. I tried to use Nodes to implement the below case but Java is importing this import org.w3c.dom.Node (document object model) so got stuck.
Insertion Cases
Insert into Empty Array
If value to be inserted less than everything, insert in the beginning.
If value to be inserted greater than everything, insert in the last.
Could be in between if value less than/greater than certain values in LL.
import java.util.*;
public class MainLinkedList {
public static void main(String[] args) {
LinkedList<Integer> llist = new LinkedList<Integer>();
llist.add(10);
llist.add(30);
llist.add(50);
llist.add(60);
llist.add(90);
llist.add(1000);
System.out.println("Old LinkedList " + llist);
//WHat if you want to insert 70 in a sorted LinkedList
LinkedList<Integer> newllist = insertSortedLL(llist, 70);
System.out.println("New LinkedList " + newllist);
}
public static LinkedList<Integer> insertSortedLL(LinkedList<Integer> llist, int value){
llist.add(value);
Collections.sort(llist);
return llist;
}
}
If we use listIterator the complexity for doing get will be O(1).
public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {
private static final long serialVersionUID = 1L;
public boolean orderedAdd(T element) {
ListIterator<T> itr = listIterator();
while(true) {
if (itr.hasNext() == false) {
itr.add(element);
return(true);
}
T elementInList = itr.next();
if (elementInList.compareTo(element) > 0) {
itr.previous();
itr.add(element);
System.out.println("Adding");
return(true);
}
}
}
}
This might serve your purpose perfectly:
Use this code:
import java.util.*;
public class MainLinkedList {
private static LinkedList<Integer> llist;
public static void main(String[] args) {
llist = new LinkedList<Integer>();
addValue(60);
addValue(30);
addValue(10);
addValue(-5);
addValue(1000);
addValue(50);
addValue(60);
addValue(90);
addValue(1000);
addValue(0);
addValue(100);
addValue(-1000);
System.out.println("Linked List is: " + llist);
}
private static void addValue(int val) {
if (llist.size() == 0) {
llist.add(val);
} else if (llist.get(0) > val) {
llist.add(0, val);
} else if (llist.get(llist.size() - 1) < val) {
llist.add(llist.size(), val);
} else {
int i = 0;
while (llist.get(i) < val) {
i++;
}
llist.add(i, val);
}
}
}
This one method will manage insertion in the List in sorted manner without using Collections.sort(list)
You can do it in log (N) time Complexity simply. No need to iterate through all the values. you can use binary search to add value to sorted linked list.just add the value at the position of upper bound of that function.
Check code... you may understand better.
public static int ubound(LinkedList<Integer> ln, int x) {
int l = 0;
int h = ln.size();
while (l < h) {
int mid = (l + h) / 2;
if (ln.get(mid) <= x) l = mid + 1;
else h = mid;
}
return l;
}
public void solve()
{
LinkedList<Integer> ln = new LinkedList<>();
ln.add(4);
ln.add(6);
ln.add(ubound(ln, 5), 5);
out.println(ln);
}
Output : [4, 5, 6]
you can learn about binary search more at : https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/
#Atrakeur
"sorting all the list each time you add a new element isn't efficient"
That's true, but if you need the list to always be in a sorted state, it is really the only option.
"The best way is to insert the element directly where it has to be (at his correct position). For this, you can loop all the positions to find where this number belong to"
This is exactly what the example code does.
"or use Collections.binarySearch to let this highly optimised search algorithm do this job for you"
Binary search is efficient, but only for random-access lists. So you could use an array list instead of a linked list, but then you have to deal with memory copies as the list grows. You're also going to consume more memory than you need if the capacity of the list is higher than the actual number of elements (which is pretty common).
So which data structure/approach to take is going to depend a lot on your storage and access requirements.
[edit]
Actually, there is one problem with the sample code: it results in multiple scans of the list when looping.
int i = 0;
while (llist.get(i) < val) {
i++;
}
llist.add(i, val);
The call to get(i) is going to traverse the list once to get to the ith position. Then the call to add(i, val) traverses it again. So this will be very slow.
A better approach would be to use a ListIterator to traverse the list and perform insertion. This interface defines an add() method that can be used to insert the element at the current position.
Have a look at com.google.common.collect.TreeMultiset.
This is effectively a sorted set that allows multiple instances of the same value.
It is a nice compromise for what you are trying to do. Insertion is cheaper than ArrayList, but you still get search benefits of binary/tree searches.
Linked list isn't the better implementation for a SortedList
Also, sorting all the list each time you add a new element isn't efficient.
The best way is to insert the element directly where it has to be (at his correct position).
For this, you can loop all the positions to find where this number belong to, then insert it, or use Collections.binarySearch to let this highly optimised search algorithm do this job for you.
BinarySearch return the index of the object if the object is found in the list (you can check for duplicates here if needed) or (-(insertion point) - 1) if the object isn't allready in the list (and insertion point is the index where the object need to be placed to maintains order)
You have to find where to insert the data by knowing the order criteria.
The simple method is to brute force search the insert position (go through the list, binary search...).
Another method, if you know the nature of your data, is to estimate an insertion position to cut down the number of checks. For example if you insert 'Zorro' and the list is alphabetically ordered you should start from the back of the list... or estimate where your letter may be (probably towards the end).
This can also work for numbers if you know where they come from and how they are distributed.
This is called interpolation search: http://en.wikipedia.org/wiki/Interpolation_search
Also think about batch insert:
If you insert a lot of data quickly you may consider doing many insertions in one go and only sort once afterwards.
Solution of Amruth, simplified:
public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {
private static final long serialVersionUID = 1L;
public boolean orderedAdd(T element) {
ListIterator<T> itr = listIterator();
while(itr.hasNext()) {
if (itr.next().compareTo(element) > 0) {
itr.previous();
break;
}
}
itr.add(element);
}
}
Obviously it's O(n)

Poset iteration order / custom iterator implementation for a partially ordered set

I am creating a partially ordered set as an abstract data type in java, and I have to make an iterator version of the set of numbers, and an iterator for the relations. Now for the elements, I've used HashSet of integer, and for the relations, I've used an ArrayList of pairs (pairs is a class I created that takes 2 ints as parameter which basically is like (x, y)). I need to make 2 iterators, one for s and one for r, but they have to follow a certain ordering,
1. if (x, y) belong to R, then the iterator of s should return x before it returns y
2. if (x, y) and (y, z) belong to R, then iterator of r should return (x, y) before it returns (y, z)
I made a helper method that check first for to check if the element n in the set is the first element in a pair then it returns it, but I cant seem to check if it is second element, how can I check for the first element if it is returned or not?
Here is my code:
private class IntGenerator implements Iterator {
private Iterator<Integer> i;
public IntGenerator () {
i = S.iterator();
}
public boolean hasNext() {
return i.hasNext();
}
public Object next() {
int n = i.next();
for (Pair p : R) {
if (isInFirstElmPair(p, n)) return n;
else (isInSecondElmPair(p, n)) {
// should check for the first element
// if it was returned or not
}
}
}
public void remove() { throw new UnsupportedOperationException(); }
}
I would really appreciate any kind of help, or hint in this code.
Thanks
EDIT:
Okay, I've wrote the code to it after adding a new set which will hold the returned elements, and this is what I wrote:
Set<Integer> returnedNumbers = new HashSet<Integer> ();
public Object next() {
int n = i.next();
for (Pair p : R) {
if (isInSecondElmPair(p, n)) {
if (returnedNumbers.contains(p.getFirstElm())) {
returnedNumbers.add(n);
return n;
}else{
returnedNumbers.add(p.getFirstElm());
return p.getFirstElm();
}
}else{
returnedNumbers.add(n);
return n;
}
}
}
Is this code correct? Also, eclipse seems to give me an error telling me I need to return a value outside the loop, but I already returned inside for every case why does it need more?
Appreciate the help
Well, to check if a value was previously returned, you of course need to keep track of all values that were returned previously.
So in your iterator, you could define
Set<Integer> previouslyReturned = new HashSet<Integer>();
and then, before returning it in your for loop, add it there:
if (isInFirstElmPair(p, n)) {
previouslyReturned.add(n);
return n;
}
else (isInSecondElmPair(p, n)) {
if (previouslyReturned.contains(n) {
// do one thing
} else {
// do another thing
}
}
This way, however, you are constructing a set of s in the order in which it shall be returned inside the iterator. It would make sense to create this once (consider a LinkedHashSet), keep it somewhere else and iterate over it.
Generally I am not sure that this approach will lead to what you want. Do you know anything about theorder of elements in S and R? If the iteration order is arbitrary (i.e. because relations were added in unpredictable order) then the iterator will first return the first half of the first relation pair, even if that element is in the second half of another pair. Do you have to use an element HashSet and a relation List?

Categories

Resources