Building a custom iterator - java

I am making this class which is a custom Map based off a hash map. I have an add method where if you add an object the object will be the key, and its value will be 1 if the object is not currently in the list. However if you add object that is currently in the list its value will be bumped up by 1. So if I added 10 strings which were all the same, the key would be that string and the value will be 10. I understand in practice when I iterate through the map, there is actually only one object to iterate, however, I am trying to create a inner class that will define an iterator that will iterate the same object however many times its value is. I can do this by simply using for loops to construct an appropriate ArrayList and just create an iterator for that, but that is too inefficient. Is there an easy or more efficient way of doing this?

You can do it with two variables:
private T nextObj = null;
private int times = 0;
T next(){
if(times==0){
// get the next object and set the times variable to it's value in the hashmap
}
times--;
return nextObj;
}

You could use nCopies from the collections API. This will create a list with only one reference so it will be efficient. Then just return that Lists iterator. No need to create an inner class.
Assuming your Map<String, Integer> instance variable is called map, you could do the following:
Iterator<String> customIteratorForKey(String key) {
return Collections.nCopies(map.get(key), key).iterator();
}

It sounds like you're implementing a multiset or bag: a set that counts each unique element. Since this is a school project, I'll give some pointers on how to do it instead of providing code. Try your luck with it and refine your question if you get stuck.
When I create a new collection type that uses another collection behind it, I typically do the same thing when building the iterator.
Bag.Iterator's constructor would initialize itself with an iterator from the Map.
As dtech showed above, the iterator needs to track the current object it is counting and the number of times it should return it.
next() needs to get the next object at the start and once the current object runs out of counts.
hasNext() must do the same thing without actually decreasing the count or grabbing the next object.

I finally figured it out. Here is my solution. Thanks to everyone who responded and gave me pointers.
private int times = 0;
private boolean flag = true;
Iterator<Entry<T, Integer>> it = Bag.entrySet().iterator();
private Entry<T, Integer> t = it.next();
private int value = t.getValue();
private T nextObj = t.getKey();
public boolean hasNext() {
if (times > 0) {
return true;
}
return it.hasNext();
}
public T next() {
if (this.hasNext() == false) {
throw new NoSuchElementException();
}
if (times == 0 && flag == true) {
times = value;
flag = false;
}
if (times == 0 && flag == false) {
t = it.next();
value = t.getValue();
nextObj = t.getKey();
times = value;
}
times--;
return nextObj;
}

Related

how do i remove an object from an ArrayList by passing a String parameter rather than passing the object itself? [duplicate]

I am maintaining one ArrayList of objects. And my object structure is Id, name, some other details. I need to remove one the object with some id value say(10) and I don't want to iterate over the list. Is there any solution for this?
Using Java-8 Collection#removeIf
myList.removeIf(obj -> obj.id == 10);
With Java-7 you'll have to use iterator:
for(Iterator<MyType> iterator = myList.iterator(); iterator.hasNext(); ) {
if(iterator.next().id == 10)
iterator.remove();
}
Note that list iteration is necessary in any case. In Java-8 removeIf method it's just performed internally.
Maybe I don't understand the question but why nobody suggested to use override equals and hashcode for that user class?
class MyObject {
final String id;
final String name;
MyObject(String id, String name) {
this.id = id;
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return Objects.equals(id, ((MyObject) o).id);
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
#Override
public String toString() {
return "MyObject{id='" + id + "', name='" + name + "'}";
}
}
in this case you can easy remove any object from list
final ArrayList<MyObject> list = new ArrayList<>();
list.add(new MyObject("id1", "name1"));
list.add(new MyObject("id2", "name2"));
list.add(new MyObject("id3", "name3"));
MyObject removeCandidate = new MyObject("id2", "name2");
list.remove(removeCandidate);
System.out.println(list);
code above prints
[MyObject{id='id1', name='name1'}, MyObject{id='id3', name='name3'}]
If you really do not want to iterate over the list, you could use a stream but I personnally prefer Collection#removeIf like #TagirValeev suggested
myList = myList.stream()
.filter(x -> x.id() != 10)
.collect(Collectors.toList());
It is not possible1 to remove instances of an element from an ArrayList without iterating the list in some way2. The ArrayList is an array under the hood, and you need to examine each element in the array to see whether it matches the criteria for removal. At the fundamental level, that entails a loop ... to iterate over the elements.
Also note that when you remove a single element from an array, all elements with positions after the removed elements need to be moved. On average, that will be half of the array elements.
Now, you can code these operations in ways that avoid you using an explicit for loop, but the iteration will be happening behind the scenes, no matter how you code it.
1 - Not strictly true. Hypothetically, if you had a separate data structure that (for instance) mapped values to the indexes of elements in the ArrayList, then you could remove the elements without iterating. But I can't see how you could manage that data structure efficiently.
2 - Iteration doesn't just mean using an Iterator. For loops, Stream, Collections.removeIf and other solutions all entail iterating the elements of the list under the hood.
You could not do that without iterator, you should you Hashmap for this.
public class ObjectStructure{
private int Id;
private String name;
//and any data field you need
}
generate all setters and getters.
Use this class in
Hashmap<Integer, ObjectStructure> data = new HashMap<>();
you can add and delete data with only key which is Integer.
data.remove(10);

Java program to count positive values in a Collection<Integer>

I am working on a program to count the positive values in an integer Collection and having an issue. I am somewhat new to Java, and wondering if someone would be able to point out where I went wrong.
public class CountPositives {
/**
* Returns the number of positive values in the given Collection.
*/
public static int countPositives(Collection<Integer> collection) {
List<Integer> copy = new ArrayList(collection);
int positive = 0;
Iterator<Integer> itr = copy.iterator();
for (int i = 0; i < copy.size(); i++) {
if (copy.get(i) > 0 ) {
positive ++;
}
}
return positive;
}
}
Your code works fine for me. (Although you have an Iterator you never use) However..
Maybe an easier way would be to do:
return (int) copy.stream().filter(e -> e > 0).count();
Which will filter out all the non positive numbers and then return the count of them. Also you can simply use the passed Collection:
public static int countPositive(Collection<Integer> collection) {
return (int)collection.stream().filter(e -> e > 0).count();
}
Which will eliminate the copy List and the extra variables.
Note that count() returns a long. If the size of collection might exceed the limit of an int, you will want to change the return type to long and not cast to an int.
You're not using the Iterator. Collections can automatically give you an iterator, so there's no need to convert it to an ArrayList to get this.
Iterator<Integer> itr = collection.iterator();
Now you actually have to use it. The for statement may look wonky to you as a beginner, but remember that a for statement starts with an optional initialization step, which can be omitted.
for(; itr.hasNext();) {
Integer value = itr.next();
// rest of your logic here
}
If you prefer, you can initialize the iterator in the for statement directly.
for(Iterator<Integer> itr = collection.iterator(); itr.hasNext();) {
Integer value = itr.next();
// rest of your logic here
}
In spite of the wasteful copying, the code appears to be fine. The critical part of the code is checking to see if there are positive values, and your code does accomplish that. This is simply making it cleaner and less ceremonious.

Update HashMap/ArrayList passed to PriorityQueue Comparator

I wrote a comparator for a PriorityQueue so that it will give me the smallest value based on the first value in the ArrayList from the HashMap.
My issue is that, in the rest of my program I need to update/change those first values in the ArrayList. I'm not sure how to do that to make sure the priority queue always gives me the proper result based on the updates?
Thanks
public class MyComparator implements Comparator<Integer>{
HashMap<Integer, ArrayList<Integer>> hm;
public MyComparator(HashMap<Integer, ArrayList<Integer>> hm){
this.hm = hm;
}
#Override
public int compare (Integer num, Integer num1){
ArrayList<Integer> list = hm.get(num);
int w = list.get(0);
ArrayList<Integer> list1 = hm.get(num1);
int w1 = list1.get(0);
if(w1 - w == 0){
return 0;
}
if(w1 - w <= 0){
return 1;
}
else{
return -1;
}
}
}
If you change the value that you're using as a key in a PriorityQueue, you need to adjust the queue to reflect the change. Otherwise, your queue will potentially be in an invalid state. The data structure can't keep track of changes you make to whatever value you're using as a key. If you change the keys, you have to notify the data structure that things changed.
The queue pointedly will not re-organize itself whenever you call peek. All peek does is return the first item in the queue. The only comparison it makes is to see if the queue is empty.
The only way to re-organize a Java PriorityQueue is to remove the element that you changed, and then re-insert it.

Remove object from ArrayList with some Object property

I am maintaining one ArrayList of objects. And my object structure is Id, name, some other details. I need to remove one the object with some id value say(10) and I don't want to iterate over the list. Is there any solution for this?
Using Java-8 Collection#removeIf
myList.removeIf(obj -> obj.id == 10);
With Java-7 you'll have to use iterator:
for(Iterator<MyType> iterator = myList.iterator(); iterator.hasNext(); ) {
if(iterator.next().id == 10)
iterator.remove();
}
Note that list iteration is necessary in any case. In Java-8 removeIf method it's just performed internally.
Maybe I don't understand the question but why nobody suggested to use override equals and hashcode for that user class?
class MyObject {
final String id;
final String name;
MyObject(String id, String name) {
this.id = id;
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return Objects.equals(id, ((MyObject) o).id);
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
#Override
public String toString() {
return "MyObject{id='" + id + "', name='" + name + "'}";
}
}
in this case you can easy remove any object from list
final ArrayList<MyObject> list = new ArrayList<>();
list.add(new MyObject("id1", "name1"));
list.add(new MyObject("id2", "name2"));
list.add(new MyObject("id3", "name3"));
MyObject removeCandidate = new MyObject("id2", "name2");
list.remove(removeCandidate);
System.out.println(list);
code above prints
[MyObject{id='id1', name='name1'}, MyObject{id='id3', name='name3'}]
If you really do not want to iterate over the list, you could use a stream but I personnally prefer Collection#removeIf like #TagirValeev suggested
myList = myList.stream()
.filter(x -> x.id() != 10)
.collect(Collectors.toList());
It is not possible1 to remove instances of an element from an ArrayList without iterating the list in some way2. The ArrayList is an array under the hood, and you need to examine each element in the array to see whether it matches the criteria for removal. At the fundamental level, that entails a loop ... to iterate over the elements.
Also note that when you remove a single element from an array, all elements with positions after the removed elements need to be moved. On average, that will be half of the array elements.
Now, you can code these operations in ways that avoid you using an explicit for loop, but the iteration will be happening behind the scenes, no matter how you code it.
1 - Not strictly true. Hypothetically, if you had a separate data structure that (for instance) mapped values to the indexes of elements in the ArrayList, then you could remove the elements without iterating. But I can't see how you could manage that data structure efficiently.
2 - Iteration doesn't just mean using an Iterator. For loops, Stream, Collections.removeIf and other solutions all entail iterating the elements of the list under the hood.
You could not do that without iterator, you should you Hashmap for this.
public class ObjectStructure{
private int Id;
private String name;
//and any data field you need
}
generate all setters and getters.
Use this class in
Hashmap<Integer, ObjectStructure> data = new HashMap<>();
you can add and delete data with only key which is Integer.
data.remove(10);

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