I have a TreeSet in JAVA which orders a custom datatype called 'Node'. However, the TreeSet does not order itself properly.
A link to my complete implementation is at the bottom. Let me explain my probelm in detail first
Here have a custome datatype 'Node'. It has 2 parameters as such. A character and a number associated to it. Say something like:
pair<char,int> node;
in C++.
Here is the code:
class Node
{
char c;int s;
Node(char x,int y)
{
c=x;s=y;
}
}
I implemented a Comparator for this TreeSet which order the elements in descending order of 's'. So for example we have 2 nodes one is (a,2) and the other is (b,5), the they will be ordered as (b,5);(a,2). However, if their size is the same, the lexicographically smaller character will come first.
TreeSet<Node> ts=new TreeSet<Node>(new Comparator<Node>()
{
#Override
public int compare(Node o1, Node o2)
{
if(o2.s!=o1.s)
{
return o2.s-o1.s;
}
return (o1.c-o2.c);
}
});
Now i input the values as Following:
ts.add(new Node('a',3));
ts.add(new Node('b',2));
ts.add(new Node('c',1));
Now here is the operation I want to perform:
Pick the element at the head of the TreeSet. Call it a node. Print it
Check for 's' or the number associated with this node. Reduce it by 1
If s becomes 0, remove the node all together from the TreeSet
Keep performing this expression till the TreeSet is empty
Here is my implementaion:
while(ts.size()!=0)
{
Node node=ts.first();
System.out.println(node.c+" "+node.s);//Printing the character and the number associated with it
if(node.s==1)
{
ts.pollFirst();//removing redundant node as reducing it by 1 will become 0
}
else
{
ts.first().s--;//Reducing it's size
}
}
Well here is my probelem:
Current Output: Expected Output:
a 3 a 3
a 2 a 2
a 1 //In this iteration, b has the largest number b 2
b 2 a 1
b 1 b 1
c 1 c 1
Why is the TreeSet not reordering itself and behaving more like a List? How do I rectify this?
I've gotten used to the idea of a 'Comparator' quite recently so please excuse me for a few goof ups in the implementation if any.
Here is the complete implementation: http://ideone.com/As35FO
The TreeSet won't reorder itself when you change the value of the elements. You have to take the elements out and re-add them if you want them to remain ordered:
Node first = ts.pollFirst();
first.s--;
ts.add(first);
Related
I am working on 2D array and I need to organize my array.
Explanation, my array is an Array String and it's containing in the header some double value, and I want to sort the array in function of the header.
The first thing I thought was to get the header and sort the header, get all the columns of the array in another array and comparate the value of the header ordered to each column index[0] and push to another array.
However, I thought there is a way to do it easily, but I don't know if there is, I saw the possibility to sort directly in the array and organize in function of this but I have no idea how to it.
Just in case :
Original array
String[][]myArray = {{3,Toto,30},{2,Tata,29},{1,Titi,13}};
Array expected
String[][]newArray = {{1,Titi,13},{2,Tata,29},{3,Toto,30}};
Open to proposal!
Thanks.
Edit : The header could be Double value.
If I understood you correctly, seems like this:
Arrays.stream(myArray)
.sorted(Comparator.comparingDouble(x -> Double.valueOf(x[0])))
.toArray(String[][]::new);
Of course you can do that in place too, via Arrays::sort and that Comparator
Previous answer just returned the original array when I tried it. Here's what worked for me:
String[][] myArray = {{"3","Toto","30"},{"2","Tata","29"},{"1","Titi","13"}};
Arrays.sort(myArray, new Comparator<String[]>() {
public int compare(String[] lhs, String[] rhs) {
try {
double lhs_value = Double.parseDouble(lhs[0]);
double rhs_value = Double.parseDouble(rhs[0]);
if (lhs_value < rhs_value) return -1;
if (lhs_value > rhs_value) return 1;
return 0; //else the two are equal
} catch (NumberFormatException e) {
//handle exception
return 0;
}
}
});
My output:
1 Titi 13
2 Tata 29
3 Toto 30
Here Arrays.sort (see Javadoc) takes in two parameters: an array you're sorting (myArray), and a Comparator (see Javadoc), which is an interface that allows comparison between two arbitrary types. Since {"3", "Toto", "30"} isn't a type you created, and is just a String[], we're going to make a Comparator<String[]> inline.
Comparators implement a function "compare" which takes in two elements, and returns -1, 0, or 1 to determine the ordering of the elements. Essentially "compare" gets called multiple times in the sorting process to precisely determine sorted order. Here's some pseudocode:
public int compare(Object a, Object b)
if (a comes "before" b) return -1
if (a is "equal" to b) return 0
if (a comes "after" b) return 1
If that isn't clear, you can learn more about the Comparator interface here:
https://www.geeksforgeeks.org/comparator-interface-java/
I know I used "before" and "after" earlier, which are a little fuzzy and non-rigorous. If you're more mathematically inclined, here's a good discussion of the Comparator interface:
https://math.stackexchange.com/questions/1400655/java-comparator-documentation-confused-about-the-terminology-total-order
This question already has answers here:
Iterating through PriorityQueue doesn't yield ordered results
(3 answers)
Closed 5 years ago.
I'm implementing a sample order book (in Exchange domain) and I'm implementing the buy and the sell sides using PriorityQueue in Java.
Buy side should be descending and sell side should be ascending.
PriorityQueue<ArrayList<Order>> bookSide;
Each side consists of price points, and each point has a list of Orders.
My buy side works fine.
This is my sell side. I want this is to be ordered descending.
sellSide = new PriorityQueue<ArrayList<Order>>(new Comparator<ArrayList<Order>>() {
#Override
public int compare(ArrayList<Order> arg0, ArrayList<Order> arg1) {
// below two conditions are highly unlikely to happen
// as the the elements are added to the list before the list is
// added to the queue.
if (arg0.size() == 0) {
return -1;
}
if (arg1.size() == 0) {
return -1;
}
// all the elements in a list have a similar price
Order o1 = arg0.get(0);
Order o2 = arg1.get(0);
int r = (int) (o1.getPrice() - o2.getPrice());
return r;
}
});
I add 100,100,101 and 99.
When 101 is added, it correctly adds 101 below 100 (list of 100). But when I add 99, it destroys the order and becomes 99,101,100.
I have no clue what is wrong.
Please help me out.
EDIT
This is how I add the elements to the lists. The price is a long.
ArrayList<Order> pricePoint = sidePoints.get(price);
if (pricePoint == null) {
pricePoint = new ArrayList<>();
pricePoint.add(order); // I want the list to be non-empty when adding to queue
bookSide.add(pricePoint);
} else {
pricePoint.add(order);
}
It seems there's a misunderstanding about how PriorityQueue works.
Let's try to clear that up.
But when I add 99, it destroys the order and becomes 99,101,100.
First, an important reminder from the Javadoc of PriorityQueue:
An unbounded priority queue based on a priority heap.
The key term here is heap.
In a heap, elements are not ordered in a sequence.
A heap is a tree-like structure,
where every node is consistently ordered compared to every other node below it.
In other words,
there are no guarantees whatsoever with respect to ordering of nodes at the same level.
A heap in ascending order (min heap) will guarantee that the top element is the smallest.
After you pop the top element,
the next top element will be the smallest of the remaining elements.
And so on.
If you want a list of sorted elements,
you have to build it by popping from the heap one by one.
Alternatively,
you can use just a list,
and sort it using Collections.sort.
As an aside,
and as others pointed out in comments,
the implementation of the compare method violates the contract of the Comparator interface:
when precisely one of a and b is empty,
both compare(a, b) and compare(b, a) returns -1,
which implies that a < b and b < a,
which breaks logic.
The fix is easy, I also simplified a bit the rest of the implementation:
#Override
public int compare(ArrayList<Order> arg0, ArrayList<Order> arg1) {
if (arg0.isEmpty()) {
return -1;
}
if (arg1.isEmpty()) {
return 1;
}
return Integer.compare(arg0.get(0).getPrice(), arg1.get(0).getPrice());
}
Given the head of a linked list and the int to search for as parameters, I need a method that will remove the first occurrence of this number in the list, and return the modified list. however i cannot modify the original list. I know how to remove the node from the list, but im not sure how i would keep the original list intact since this has to be done recursively. below is the method
** initially M is the original list. I dont know that it will still be the same list after calling the method again...?
MyList removeNumber(MyList m, int removee){
The idea is that the resulting structure will be a "Y": a two-headed list (actually a simple graph).
One branch of the Y is the original list. The other is your new list with removed node. The vertical stalk of the Y is what's after the element you remove. It's common to both lists. Here's some ascii art with the Y turned on its side showing a list of 1 to 5 with 3 removed.
new -> 1 -> 2 ------\
v
original -> 1 -> 2 -> 3 -> 4 -> 5 -> null
Thinking recursively is all about defining a problem in terms of a smaller version of itself plus a fixed bit of work. And you need a base case (or maybe several).
A linked list is itself a recursive structure:
A list is either empty or it's an element linked by its "next" reference to a list.
Note this defines a list using a smaller list. The base case is the empty list. The fixed bit is the element.
Read this definition a few times, then see how it translates the code:
class MyList {
int value; // the element at the head of this list
MyList next; // the rest of the list
MyList(int value, MyList next) {
this.value = value;
this.next = next;
}
}
The base case "empty list" is just a null reference. The element removal problem expressed recursively using the same pattern becomes:
A copy of a list with an element removed is either a) the rest of the list following the head in the case that the element to be removed is the head or b) a copy of the current node followed by a copy the rest of the list with the desired element removed.
Here I'm defining a "copy of a list with one element removed" using a smaller version of the same thing. Case a) is the base case. The fixed bit is copying the head when it's not the removee.
Of course there's another base case: if the list is empty, the removee can't be found. That's an error.
Putting this in code:
MyList removeNumber(MyList m, int removee) {
if (m == null) throw new RuntimeException("removee not found");
if (m.value == removee) return m.next;
return new MyList(m.value, removeNumber(m.next, removee));
}
Putting the function to use would look something like this:
MyList originalList = ... // list of 1 to 5.
MyList newListWith3removed = removeNumber(originalList, 3);
System.out.println("Original list:");
for (MyList p : originalList) System.out.println(p.value);
System.out.println("With 3 removed:");
for (MyList p : newListWith3removed) System.out.println(p.value);
The output will look as expected: 1 to 5 in the first list and 1,2,4,5 in the second. I.e. the first list is unchanged.
//This function will always return a new list with 'remove' removed
MyList removeNumber(MyList m, int remove){
//if m is empty List, return an empty list
//if head is not the int to remove, return a New list from
// head concat removeNumber(m.next,remove)
//else return removeNumber(m.next,remove)
}
I think it lacks information. I'm assuming however a very traditional implementation for linked list, for instance:
class MyList {
MyList prev;
MyList next;
int data;
static MyList removeNumber(MyList m,int removee) {
if(m == null) return null; // already empty
if(m.data == removee) { // m already is the node to throw away
if(m.prev != null)// relink
m.prev.next = m.next;
if(m.next != null)// relink
m.next.prev = m.prev;
return m.prev;
}
// if this node isn't the one yet, keep looking for
return removeNumber(m.next,removee);
}
}
There are plenty different ways to do that, but you have to provide more info in order to allow us to point you the correct literature.
I'm looking for some kind of set data structure that can meet both of these requirements:
Sorted
O(1) for lookup
This is what I got so far, but I really hope there's an existing, less-awkward, data structure out there.
/**
* This MUST support both
* (1) Looking up by A - O(n)
* (2) Iteration by sorted Foo<A, B>
*/
public class MySet<Foo<A, B>> extends TreeSet<Foo<A, B>>
{
private Map<A, Foo<A, B>> temp = new HashMap<A, Foo<A, B>>();
public Foo<A, B> getNode(A a)
{
return temp.get(a);
}
#Override
public boolean add(Foo<A, B> foo)
{
temp.put(foo.getA(), foo);
return super.add(foo);
}
}
And my Foo class looks like this:
public class Foo<A, B>
{
private A a; //Can NEVER be null
private B b; //Can NEVER be null
//... constructor and stuff omitted
public int compareTo(Foo<A, B> that)
{
if (this.equals(that))
return 0;
//Compare by a first
int ret = this.a.compareTo(that);
if (ret == 0)
return 0;
//Compare by b
return this.b.compareTo(that.b);
}
public boolean equals(Object obj)
{
if (!(obj instanceof Foo))
return false;
Foo rhs = (Foo) obj;
return this.a.equals(rhs.a) && this.b.equals(rhs.b);
}
}
UPDATE:
Here's a use case for my set:
MySet<Foo<SomeA, SomeB>> mySet = getTheData(); //getTheData() returns a set with a bunch of Foo objects
SomeA a = getA(); //getA() returns some instance of SomeA that I'm interested in
I want to be able to check the set and RETRIEVE a Foo object (if exists) such that Foo.getA() == a;
mySet.getNode(a);
You can get it by using some additional space. So you need a HashSet. Additionally, each element will point to the next value in the sort order. Let's say you have keys 1, 3, 5, 10 and you are using linear probing.
value array = [3, 5, null, null, 10, 1];
pointer array = [1, 4, null, null, null, 0];
So the value array contains the values. The hash function decides where the value goes. so in the above example, h(1) = 5 (1 goes to index 5), h(3) = 0, h(5) = 1, and h(10) = 4. The indexes 2, 3 have null (open spaces for future elements). The pointer array says which element follows the current element in the sorting order. So let's say we are doing set.contains(3), it will result in computing h(3) (which will yield 0), and we know that the element exists in the set. If we want the next element in the set of elements according to sort order, we look at the value in the pointer array. So for value 3 (which is at position 0 in the value array), we get the next element in the sort order by looking up the index in the pointer array (pointer_array[0], which is 1), and then looking up value_array[1], which is 5.
This is a very common implementation. Java's LinkedHashMap is usually used as a LRU cache, which is implemented as a hash map + a doubly linked list of keys. The keys in the doubly linked list are in the order of their access.
In your case, when you insert an element, you need to adjust your pointer array which is very slow. You have to do a linear scan. If this is not read only, you can use the following approach.
In your data structure, have a hashset and a avl tree, a red black tree or any other balanced binary tree. Whenever you do a containsKey test, it's O(1). Whenever you are enumerating, you can traverse them using the binary tree in sorted order in linear time. Whenever you are inserting a new element, you also insert it into both the binary tree and HashSet. When you delete, you delete the element from the hash set and the binary tree. So deletes and inserts become O(log n).
I think you should try using MultiMaps in google guava library.
Its pretty simple to use also:
Map<Salesperson, List<Sale>> map = new Hashmap<SalesPerson, List<Sale>>();
public void makeSale(Salesperson salesPerson, Sale sale) {
List<Sale> sales = map.get(salesPerson);
if (sales == null) {
sales = new ArrayList<Sale>();
map.put(salesPerson, sales);
}
sales.add(sale);
}
can be replaced by,
Multimap<Salesperson, Sale> multimap = new ArrayListMultimap<Salesperson,Sale>();
public void makeSale(Salesperson salesPerson, Sale sale) {
multimap.put(salesperson, sale);
}
But you have to be careful here, multimaps will preserve the entries with same keys unlike hashmaps which replaces the equivalent keys with the latest one.
Google Guava Libraries feature a lot of other data structures with different functionality. You can find the information about it on its wiki.
Hope this was helpful.
I have a java.util.ArrayList<Item> and an Item object.
Now, I want to obtain the number of times the Item is stored in the arraylist.
I know that I can do arrayList.contains() check but it returns true, irrespective of whether it contains one or more Items.
Q1. How can I find the number of time the Item is stored in the list?
Q2. Also, If the list contains more than one Item, then how can I determine the index of other Items because arrayList.indexOf(item) returns the index of only first Item every time?
You can use Collections class:
public static int frequency(Collection<?> c, Object o)
Returns the number of elements in the specified collection equal to the specified object. More formally, returns the number of elements e in the collection such that (o == null ? e == null : o.equals(e)).
If you need to count occurencies of a long list many times I suggest you to use an HashMap to store the counters and update them while you insert new items to the list. This would avoid calculating any kind of counters.. but of course you won't have indices.
HashMap<Item, Integer> counters = new HashMap<Item, Integer>(5000);
ArrayList<Item> items = new ArrayList<Item>(5000);
void insert(Item newEl)
{
if (counters.contains(newEl))
counters.put(newEl, counters.get(newEl)+1);
else
counters.put(newEl, 1);
items.add(newEl);
}
A final hint: you can use other collections framework (like Apache Collections) and use a Bag datastructure that is described as
Defines a collection that counts the number of times an object appears in the collection.
So exactly what you need..
This is easy to do by hand.
public int countNumberEqual(ArrayList<Item> itemList, Item itemToCheck) {
int count = 0;
for (Item i : itemList) {
if (i.equals(itemToCheck)) {
count++;
}
}
return count;
}
Keep in mind that if you don't override equals in your Item class, this method will use object identity (as this is the implementation of Object.equals()).
Edit: Regarding your second question (please try to limit posts to one question apiece), you can do this by hand as well.
public List<Integer> indices(ArrayList<Item> items, Item itemToCheck) {
ArrayList<Integer> ret = new ArrayList<Integer>();
for (int i = 0; i < items.size(); i++) {
if (items.get(i).equals(itemToCheck)) {
ret.add(i);
}
}
return ret;
}
As the other respondents have already said, if you're firmly committed to storing your items in an unordered ArrayList, then counting items will take O(n) time, where n is the number of items in the list. Here at SO, we give advice but we don't do magic!
As I just hinted, if the list gets searched a lot more than it's modified, it might make sense to keep it sorted. If your list is sorted then you can find your item in O(log n) time, which is a lot quicker; and if you have a hashcode implementation that goes well with your equals, all the identical items will be right next to each other.
Another possibility would be to create and maintain two data structures in parallel. You could use a HashMap containing your items as keys and their count as values. You'd be obligated to update this second structure any time your list changes, but item count lookups would be o(1).
I could be wrong, but it seems to me like the data structure you actually want might be a Multiset (from google-collections/guava) rather than a List. It allows multiples, unlike Set, but doesn't actually care about the order. Given that, it has a int count(Object element) method that does exactly what you want. And since it isn't a list and has implementations backed by a HashMap, getting the count is considerably more efficient.
Thanks for your all nice suggestion. But this below code is really very useful as we dont have any search method with List that can give number of occurance.
void insert(Item newEl)
{
if (counters.contains(newEl))
counters.put(newEl, counters.get(newEl)+1);
else
counters.put(newEl, 1);
items.add(newEl);
}
Thanks to Jack. Good posting.
Thanks,
Binod Suman
http://binodsuman.blogspot.com
I know this is an old post, but since I did not see a hash map solution, I decided to add a pseudo code on hash-map for anyone that needs it in the future. Assuming arraylist and Float data types.
Map<Float,Float> hm = new HashMap<>();
for(float k : Arralistentry) {
Float j = hm.get(k);
hm.put(k,(j==null ? 1 : j+1));
}
for(Map.Entry<Float, Float> value : hm.entrySet()) {
System.out.println("\n" +value.getKey()+" occurs : "+value.getValue()+" times");
}