What edits should I make to my constructor? [duplicate] - java

This question already has answers here:
How can I set the count of an item in a list<T> to a specific amount
(2 answers)
Closed 3 months ago.
I am trying to implement some functions to a generic array such as setting the count of the item to int count via method setcount( DT item, int count). I've asked this before and a kind Stack Overflow user has been nice enough to explain that using a hashmap would've been better.
class SimpleHistogram<T> implements Histogram<T>, Iterable<T> {
private final Map<T, Integer> bins = new HashMap<>();
public SimpleHistogram() {
this(List.of());
}
SimpleHistogram(List<? extends T> items) {
for (T item : items) {
Integer count = bins.getOrDefault(item, 0);
bins.put(item, count + 1);
}
}
#Override
public void setCount(T item, int count) {
bins.put(item, count);
}
#Override
public Iterator<T> iterator() {
return bins.keySet().iterator();
}
}
#Override
public int getTotalCount() {
return bins.size();
}
However, there seems to be an error when I tried to run it using my test cases and it seems that the issue stems from the constructor that I'm provided with.
I've tried to debug the issue but the only solution available is to change from
public SimpleHistogram() {
this(List.of());
}
to
public SimpleHistogram(Character[] target) {
this(List.of());
}
which would be wrong since it should take in any generic array.
Any suggestions on what changes should I make?
Here are the test cases by the way:
public class SimpleHistogramTest {
#Test
public void testHistogram() {
Character[] target = {'a','b','c','a'};
Histogram<Character> h = new SimpleHistogram<>(target); //here is where the problem arises
Iterator<Character> iter = h.iterator();
int elemCount = 0;
while(iter.hasNext()) {
iter.next();
elemCount++;
}
assertEquals(3, elemCount);
assertEquals(2, h.getCount('a'));
assertEquals(1, h.getCount('b'));
assertEquals(1, h.getCount('c'));
assertEquals(4, h.getTotalCount());

You should overload your constructor with a new one which is handle the arrays or have to pass the array as list.
SimpleHistogram(T[] items) {
this(Arrays.asList(items));
}
or
#Test
public void testHistogram() {
Character[] target = {'a','b','c','a'};
Histogram<Character> h = new SimpleHistogram<>(Arrays.asList(target));
Iterator<Character> iter = h.iterator();
int elemCount = 0;
while(iter.hasNext()) {
iter.next();
elemCount++;
}
}
Or you can use the 3 dot syntax for parameters.
SimpleHistogram(T... items) {
this(Arrays.asList(items));
}
Formatted code for the comment answer:
Its a little missunderstand naming convention. If you want to add items, so incrase the count is: Check if the HashMap has item with key if yes then get its value and incrase with the count, you can do this by sum them and put the key again with the new value
public void addCount(T item, int count) {
if (bins.containsKey(item)){
bins.put(item, bins.get(item)+count);
}else{
bins.put(item, count);
}
}
public void setCount(T item, int count) {
bins.put(item, count);
}

Related

Why is remove() for TreeSet<String> not working?

I am trying to solve the problem at https://leetcode.com/problems/design-a-food-rating-system and this is my solution.
class FoodRatings {
class SortedSetComparator implements Comparator<String> {
public int compare(String A, String B) {
if (foodRatingMap.get(A) == foodRatingMap.get(B)) {
return A.compareTo(B);
}
return foodRatingMap.get(B).compareTo(foodRatingMap.get(A));
}
}
Map<String, SortedSet<String>> foodTypeMap;
Map<String, String> foodMap;
Map<String, Integer> foodRatingMap;
public FoodRatings(String[] foods, String[] cuisines, int[] ratings) {
foodTypeMap = new HashMap<>();
foodMap = new HashMap<>();
foodRatingMap = new HashMap<>();
for (int i = 0; i<foods.length; i++) {
foodTypeMap.putIfAbsent(cuisines[i], new TreeSet<String> (new SortedSetComparator()));
foodMap.put(foods[i], cuisines[i]);
foodRatingMap.put(foods[i], ratings[i]);
foodTypeMap.get(cuisines[i]).add(foods[i]);
}
}
public void changeRating(String food, int newRating) {
foodRatingMap.put(food, newRating);
SortedSet<String> set = foodTypeMap.get(foodMap.get(food));
if (!set.remove(food)) {
System.out.println("Unable to find " + food);
}
foodTypeMap.get(foodMap.get(food)).add(food);
}
public String highestRated(String cuisine) {
return foodTypeMap.get(cuisine).first();
}
}
Could anyone tell me why the TreeSet remove() method is not working ?
Here is the input for the same.
public static void main(String args[]) {
String[] foods = new String[] {
"czopaaeyl", "lxoozsbh", "kbaxapl"
};
String[] cuisines = new String[] {
"dmnuqeatj", "dmnuqeatj", "dmnuqeatj"
};
int[] ratings = new int[] {
11, 2, 15
};
FoodRatings obj = new MyClass().new FoodRatings(foods, cuisines, ratings);
obj.changeRating("czopaaeyl", 12);
String food = obj.highestRated("dmnuqeatj");
System.out.println(food);
obj.changeRating("kbaxapl", 8);
food = obj.highestRated("dmnuqeatj");
System.out.println(food);
obj.changeRating("lxoozsbh", 5);
food = obj.highestRated("dmnuqeatj");
System.out.println(food);
}
I am not sure why the remove function is not working properly here.
Well, it took me a while to find the problem. Besides the Integer compare issue which is only needed to sort equal ratings in lexical order. You were updating the ratings prior to doing a remove. But since your set uses this structure in its comparator, things got out of sync.
public void changeRating(String food, int newRating) {
SortedSet<String> set = foodTypeMap.get(foodMap.get(food));
if (!set.remove(food)) {
System.out.println("Unable to find " + food);
}
foodTypeMap.get(foodMap.get(food)).add(food);
foodRatingMap.put(food, newRating);
}
As soon as I moved foodRatingMap.put(food, newRating); to the bottom, it worked. BTW, I would have written a Food class hold each foods type, rating, and cuisine. Usually these test sites are only interested in results and efficiency, not how you did it.
Well. That was a very subtle issue to find. First the order in which the ratings were updated are wrong. The correct order was :-
Remove the food from the sortedSet.
Update the rating.
Add the food back to the sorted set.
Changes were done in two places.
The first one was to correct the order.
public void changeRating(String food, int newRating) {
foodTypeMap.get(foodMap.get(food)).remove(food);
foodRatingMap.put(food, newRating);
foodTypeMap.get(foodMap.get(food)).add(food);
}
The second one was to use equals() when comparing integer values in the comparator.
class SortedSetComparator implements Comparator<String> {
public int compare(String A, String B) {
if (foodRatingMap.get(A).equals(foodRatingMap.get(B))) {
return A.compareTo(B);
}
return foodRatingMap.get(B).compareTo(foodRatingMap.get(A));
}
}

How can I sort a list based on another list values in Java [duplicate]

I've seen several other questions similiar to this one but I haven't really been able to find anything that resolves my problem.
My use case is this: user has a list of items initially (listA). They reorder the items and want to persist that order (listB), however, due to restrictions I'm unable persist the order on the backend so I have to sort listA after I retrieve it.
So basically, I have 2 ArrayLists (listA and listB). One with the specific order the lists should be in (listB) and the other has the list of items (listA). I want to sort listA based on listB.
Using Java 8:
Collections.sort(listToSort,
Comparator.comparing(item -> listWithOrder.indexOf(item)));
or better:
listToSort.sort(Comparator.comparingInt(listWithOrder::indexOf));
Collections.sort(listB, new Comparator<Item>() {
public int compare(Item left, Item right) {
return Integer.compare(listA.indexOf(left), listA.indexOf(right));
}
});
This is quite inefficient, though, and you should probably create a Map<Item, Integer> from listA to lookup the positions of the items faster.
Guava has a ready-to-use comparator for doing that: Ordering.explicit()
Let's say you have a listB list that defines the order in which you want to sort listA. This is just an example, but it demonstrates an order that is defined by a list, and not the natural order of the datatype:
List<String> listB = Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday");
Now, let's say that listA needs to be sorted according to this ordering. It's a List<Item>, and Item has a public String getWeekday() method.
Create a Map<String, Integer> that maps the values of everything in listB to something that can be sorted easily, such as the index, i.e. "Sunday" => 0, ..., "Saturday" => 6. This will provide a quick and easy lookup.
Map<String, Integer> weekdayOrder = new HashMap<String, Integer>();
for (int i = 0; i < listB.size(); i++)
{
String weekday = listB.get(i);
weekdayOrder.put(weekday, i);
}
Then you can create your custom Comparator<Item> that uses the Map to create an order:
public class ItemWeekdayComparator implements Comparator<Item>
{
private Map<String, Integer> sortOrder;
public ItemWeekdayComparator(Map<String, Integer> sortOrder)
{
this.sortOrder = sortOrder;
}
#Override
public int compare(Item i1, Item i2)
{
Integer weekdayPos1 = sortOrder.get(i1.getWeekday());
if (weekdayPos1 == null)
{
throw new IllegalArgumentException("Bad weekday encountered: " +
i1.getWeekday());
}
Integer weekdayPos2 = sortOrder.get(i2.getWeekday());
if (weekdayPos2 == null)
{
throw new IllegalArgumentException("Bad weekday encountered: " +
i2.getWeekday());
}
return weekdayPos1.compareTo(weekdayPos2);
}
}
Then you can sort listA using your custom Comparator.
Collections.sort(listA, new ItemWeekdayComparator(weekdayOrder));
Speed improvement on JB Nizet's answer (from the suggestion he made himself). With this method:
Sorting a 1000 items list 100 times improves speed 10 times on my
unit tests.
Sorting a 10000 items list 100 times improves speed 140 times (265 ms for the whole batch instead of 37 seconds) on my
unit tests.
This method will also work when both lists are not identical:
/**
* Sorts list objectsToOrder based on the order of orderedObjects.
*
* Make sure these objects have good equals() and hashCode() methods or
* that they reference the same objects.
*/
public static void sortList(List<?> objectsToOrder, List<?> orderedObjects) {
HashMap<Object, Integer> indexMap = new HashMap<>();
int index = 0;
for (Object object : orderedObjects) {
indexMap.put(object, index);
index++;
}
Collections.sort(objectsToOrder, new Comparator<Object>() {
public int compare(Object left, Object right) {
Integer leftIndex = indexMap.get(left);
Integer rightIndex = indexMap.get(right);
if (leftIndex == null) {
return -1;
}
if (rightIndex == null) {
return 1;
}
return Integer.compare(leftIndex, rightIndex);
}
});
}
Problem : sorting a list of Pojo on the basis of one of the field's all possible values present in another list.
Take a look at this solution, may be this is what you are trying to achieve:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Employee> listToSort = new ArrayList<>();
listToSort.add(new Employee("a", "age11"));
listToSort.add(new Employee("c", "age33"));
listToSort.add(new Employee("b", "age22"));
listToSort.add(new Employee("a", "age111"));
listToSort.add(new Employee("c", "age3"));
listToSort.add(new Employee("b", "age2"));
listToSort.add(new Employee("a", "age1"));
List<String> listWithOrder = new ArrayList<>();
listWithOrder.add("a");
listWithOrder.add("b");
listWithOrder.add("c");
Collections.sort(listToSort, Comparator.comparing(item ->
listWithOrder.indexOf(item.getName())));
System.out.println(listToSort);
}
}
class Employee {
String name;
String age;
public Employee(String name, String age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
#Override
public String toString() {
return "[name=" + name + ", age=" + age + "]";
}
}
O U T P U T
[[name=a, age=age11], [name=a, age=age111], [name=a, age=age1], [name=b, age=age22], [name=b, age=age2], [name=c, age=age33], [name=c, age=age3]]
Here is a solution that increases the time complexity by 2n, but accomplishes what you want. It also doesn't care if the List R you want to sort contains Comparable elements so long as the other List L you use to sort them by is uniformly Comparable.
public class HeavyPair<L extends Comparable<L>, R> implements Comparable<HeavyPair<L, ?>> {
public final L left;
public final R right;
public HeavyPair(L left, R right) {
this.left = left;
this.right = right;
}
public compareTo(HeavyPair<L, ?> o) {
return this.left.compareTo(o.left);
}
public static <L extends Comparable<L>, R> List<R> sort(List<L> weights, List<R> toSort) {
assert(weights.size() == toSort.size());
List<R> output = new ArrayList<>(toSort.size());
List<HeavyPair<L, R>> workHorse = new ArrayList<>(toSort.size());
for(int i = 0; i < toSort.size(); i++) {
workHorse.add(new HeavyPair(weights.get(i), toSort.get(i)))
}
Collections.sort(workHorse);
for(int i = 0; i < workHorse.size(); i++) {
output.add(workHorse.get(i).right);
}
return output;
}
}
Excuse any terrible practices I used while writing this code, though. I was in a rush.
Just call HeavyPair.sort(listB, listA);
Edit: Fixed this line return this.left.compareTo(o.left);. Now it actually works.
Here is an example of how to sort a list and then make the changes in another list according to the changes exactly made to first array list. This trick will never fails and ensures the mapping between the items in list. The size of both list must be same to use this trick.
ArrayList<String> listA = new ArrayList<String>();
ArrayList<String> listB = new ArrayList<String>();
int j = 0;
// list of returns of the compare method which will be used to manipulate
// the another comparator according to the sorting of previous listA
ArrayList<Integer> sortingMethodReturns = new ArrayList<Integer>();
public void addItemstoLists() {
listA.add("Value of Z");
listA.add("Value of C");
listA.add("Value of F");
listA.add("Value of A");
listA.add("Value of Y");
listB.add("this is the value of Z");
listB.add("this is the value off C");
listB.add("this is the value off F");
listB.add("this is the value off A");
listB.add("this is the value off Y");
Collections.sort(listA, new Comparator<String>() {
#Override
public int compare(String lhs, String rhs) {
// TODO Auto-generated method stub
int returning = lhs.compareTo(rhs);
sortingMethodReturns.add(returning);
return returning;
}
});
// now sort the list B according to the changes made with the order of
// items in listA
Collections.sort(listB, new Comparator<String>() {
#Override
public int compare(String lhs, String rhs) {
// TODO Auto-generated method stub
// comparator method will sort the second list also according to
// the changes made with list a
int returning = sortingMethodReturns.get(j);
j++;
return returning;
}
});
}
try this for java 8:
listB.sort((left, right) -> Integer.compare(list.indexOf(left), list.indexOf(right)));
or
listB.sort(Comparator.comparingInt(item -> list.indexOf(item)));
import java.util.Comparator;
import java.util.List;
public class ListComparator implements Comparator<String> {
private final List<String> orderedList;
private boolean appendFirst;
public ListComparator(List<String> orderedList, boolean appendFirst) {
this.orderedList = orderedList;
this.appendFirst = appendFirst;
}
#Override
public int compare(String o1, String o2) {
if (orderedList.contains(o1) && orderedList.contains(o2))
return orderedList.indexOf(o1) - orderedList.indexOf(o2);
else if (orderedList.contains(o1))
return (appendFirst) ? 1 : -1;
else if (orderedList.contains(o2))
return (appendFirst) ? -1 : 1;
return 0;
}
}
You can use this generic comparator to sort list based on the the other list.
For example, when appendFirst is false below will be the output.
Ordered list: [a, b]
Un-ordered List: [d, a, b, c, e]
Output:
[a, b, d, c, e]
One way of doing this is looping through listB and adding the items to a temporary list if listA contains them:
List<?> tempList = new ArrayList<?>();
for(Object o : listB) {
if(listA.contains(o)) {
tempList.add(o);
}
}
listA.removeAll(listB);
tempList.addAll(listA);
return tempList;
Not completely clear what you want, but if this is the situation:
A:[c,b,a]
B:[2,1,0]
And you want to load them both and then produce:
C:[a,b,c]
Then maybe this?
List c = new ArrayList(b.size());
for(int i=0;i<b.size();i++) {
c.set(b.get(i),a.get(i));
}
that requires an extra copy, but I think to to it in place is a lot less efficient, and all kinds of not clear:
for(int i=0;i<b.size();i++){
int from = b.get(i);
if(from == i) continue;
T tmp = a.get(i);
a.set(i,a.get(from));
a.set(from,tmp);
b.set(b.lastIndexOf(i),from);
}
Note I didn't test either, maybe got a sign flipped.
Another solution that may work depending on your setting is not storing instances in listB but instead indices from listA. This could be done by wrapping listA inside a custom sorted list like so:
public static class SortedDependingList<E> extends AbstractList<E> implements List<E>{
private final List<E> dependingList;
private final List<Integer> indices;
public SortedDependingList(List<E> dependingList) {
super();
this.dependingList = dependingList;
indices = new ArrayList<>();
}
#Override
public boolean add(E e) {
int index = dependingList.indexOf(e);
if (index != -1) {
return addSorted(index);
}
return false;
}
/**
* Adds to this list the element of the depending list at the given
* original index.
* #param index The index of the element to add.
*
*/
public boolean addByIndex(int index){
if (index < 0 || index >= this.dependingList.size()) {
throw new IllegalArgumentException();
}
return addSorted(index);
}
/**
* Returns true if this list contains the element at the
* index of the depending list.
*/
public boolean containsIndex(int index){
int i = Collections.binarySearch(indices, index);
return i >= 0;
}
private boolean addSorted(int index){
int insertIndex = Collections.binarySearch(indices, index);
if (insertIndex < 0){
insertIndex = -insertIndex-1;
this.indices.add(insertIndex, index);
return true;
}
return false;
}
#Override
public E get(int index) {
return dependingList.get(indices.get(index));
}
#Override
public int size() {
return indices.size();
}
}
Then you can use this custom list as follows:
public static void main(String[] args) {
class SomeClass{
int index;
public SomeClass(int index) {
super();
this.index = index;
}
#Override
public String toString() {
return ""+index;
}
}
List<SomeClass> listA = new ArrayList<>();
for (int i = 0; i < 100; i++) {
listA.add(new SomeClass(i));
}
SortedDependingList<SomeClass> listB = new SortedDependingList<>(listA);
Random rand = new Random();
// add elements by index:
for (int i = 0; i < 5; i++) {
int index = rand.nextInt(listA.size());
listB.addByIndex(index);
}
System.out.println(listB);
// add elements by identity:
for (int i = 0; i < 5; i++) {
int index = rand.nextInt(listA.size());
SomeClass o = listA.get(index);
listB.add(o);
}
System.out.println(listB);
}
Of course, this custom list will only be valid as long as the elements in the original list do not change. If changes are possible, you would need to somehow listen for changes to the original list and update the indices inside the custom list.
Note also, that the SortedDependingList does currently not allow to add an element from listA a second time - in this respect it actually works like a set of elements from listA because this is usually what you want in such a setting.
The preferred way to add something to SortedDependingList is by already knowing the index of an element and adding it by calling sortedList.addByIndex(index);
If the two lists are guaranteed to contain the same elements, just in a different order, you can use List<T> listA = new ArrayList<>(listB) and this will be O(n) time complexity. Otherwise, I see a lot of answers here using Collections.sort(), however there is an alternative method which is guaranteed O(2n) runtime, which should theoretically be faster than sort's worst time complexity of O(nlog(n)), at the cost of 2n storage
Set<T> validItems = new HashSet<>(listB);
listA.clear();
listB.forEach(item -> {
if(validItems.contains(item)) {
listA.add(item);
}
});
List<String> listA;
Comparator<B> comparator = Comparator.comparing(e -> listA.indexOf(e.getValue()));
//call your comparator inside your list to be sorted
listB.stream().sorted(comparator)..
Like Tim Herold wrote, if the object references should be the same, you can just copy listB to listA, either:
listA = new ArrayList(listB);
Or this if you don't want to change the List that listA refers to:
listA.clear();
listA.addAll(listB);
If the references are not the same but there is some equivalence relationship between objects in listA and listB, you could sort listA using a custom Comparator that finds the object in listB and uses its index in listB as the sort key. The naive implementation that brute force searches listB would not be the best performance-wise, but would be functionally sufficient.
IMO, you need to persist something else. May be not the full listB, but something. May be just the indexes of the items that the user changed.
Try this. The code below is general purpose for a scenario where listA is a list of Objects since you did not indicate a particular type.
Object[] orderedArray = new Object[listA.size()];
for(int index = 0; index < listB.size(); index ++){
int position = listB.get(index); //this may have to be cast as an int
orderedArray[position] = listA.get(index);
}
//if you receive UnsupportedOperationException when running listA.clear()
//you should replace the line with listA = new List<Object>()
//using your actual implementation of the List interface
listA.clear();
listA.addAll(orderedArray);
Just encountered the same problem.
I have a list of ordered keys, and I need to order the objects in a list according to the order of the keys.
My lists are long enough to make the solutions with time complexity of N^2 unusable.
My solution:
<K, T> List<T> sortByOrder(List<K> orderedKeys, List<T> objectsToOrder, Function<T, K> keyExtractor) {
AtomicInteger ind = new AtomicInteger(0);
Map<K, Integer> keyToIndex = orderedKeys.stream().collect(Collectors.toMap(k -> k, k -> ind.getAndIncrement(), (oldK, newK) -> oldK));
SortedMap<Integer, T> indexToObj = new TreeMap<>();
objectsToOrder.forEach(obj -> indexToObj.put(keyToIndex.get(keyExtractor.apply(obj)), obj));
return new ArrayList<>(indexToObj.values());
}
The time complexity is O(N * Log(N)).
The solution assumes that all the objects in the list to sort have distinct keys. If not then just replace SortedMap<Integer, T> indexToObj by SortedMap<Integer, List<T>> indexToObjList.
To avoid having a very inefficient look up, you should index the items in listB and then sort listA based on it.
Map<Item, Integer> index = IntStream.range(0, listB.size()).boxed()
.collect(Collectors.toMap(listB::get, x -> x));
listA.sort((e1, e2) -> Integer.compare(index.get(c1), index.get(c2));
So for me the requirement was to sort originalList with orderedList. originalList always contains all element from orderedList, but not vice versa. No new elements.
fun <T> List<T>.sort(orderedList: List<T>): List<T> {
return if (size == orderedList.size) {
orderedList
} else {
var keepIndexCount = 0
mapIndexed { index, item ->
if (orderedList.contains(item)) {
orderedList[index - keepIndexCount]
} else {
keepIndexCount++
item
}
}
}}
P.S. my case was that I have list that user can sort by drag and drop, but some items might be filtered out, so we preserve hidden items position.
If you want to do it manually. Solution based on bubble sort (same length required):
public void sortAbasedOnB(String[] listA, double[] listB) {
for (int i = 0; i < listB.length - 1; i++) {
for (int j = listB.length - 1; j > i; j--) {
if (listB[j] < listB[j - 1]){
double tempD = listB[j - 1];
listB[j - 1] = listB[j];
listB[j] = tempD;
String tempS = listA[j - 1];
listA[j - 1] = listA[j];
listA[j] = tempS;
}
}
}
}
If the object references should be the same, you can initialize listA new.
listA = new ArrayList(listB)
In Java there are set of classes which can be useful to sort lists or arrays. Most of the following examples will use lists but the same concept can be applied for arrays. A example will show this.
We can use this by creating a list of Integers and sort these using the Collections.sort(). The Collections (Java Doc) class (part of the Java Collection Framework) provides a list of static methods which we can use when working with collections such as list, set and the like. So in a nutshell, we can sort a list by simply calling: java.util.Collections.sort(the list) as shown in the following example:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class example {
public static void main(String[] args) {
List<Integer> ints = new ArrayList<Integer>();
ints.add(4);
ints.add(3);
ints.add(7);
ints.add(5);
Collections.sort(ints);
System.out.println(ints);
}
}
The above class creates a list of four integers and, using the collection sort method, sorts this list (in one line of code) without us having to worry about the sorting algorithm.

Best way of calculating permutations [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm trying to figure out the best way of finding/automating all the possible permutations for a certain scenario.
I have a program which takes in a set of numbers [X, Y , Z], Each number has a predefined uncertainty. Therefore, I want to run my program against [X, Y , Z], [X+e, Y, Z] [x-e, Y, Z], [X, Y+e, Z] etc. Right now I have built an object which contains all the 27 possibilities and I'm iterating through it in order to provide my program with a new set of input. (I'll run my program 27 times with different set of inputs)
as time goes, I'd need to update my program to take in a bigger set of numbers. So I'm wondering whether there is a better way of calculating all the possible permutations my base set may have.
I'd rather know the way of implementing this instead of using any existing libraries (if there is any). I see this as a learning program. Thanks!
Instead of writing down the the 3x3x3 sets of 3 numbers by hand, you can use nested loops. If you have 3 loops, one inside the other, each running 3 times, you get 27 outputs:
double[] numbers = new double[3];
double[] e = {-1e-6, 0, 1e-6};
for (double eX : e) {
for (double eY : e) {
for (double eZ : e) {
double[] newNumbers = {numbers[0] + eX, numbers[1] + eY, numbers[2] + eZ};
// Run your program using "newNumbers". Just as an example:
System.out.println(Arrays.toString(newNumbers));
}
}
}
As for
as time goes, I'd need to update my program to take in a bigger set of numbers
If the size of the set is going to be small and fixed, you can just add more nested loops. If not, you are going to need more advanced techniques .
Here is a permutation method I found some time ago. It prints them within the method. It only does single dimension permutations but you may be able to adapt it to your needs.
public static void generate(int n, int[] a) {
if (n == 1) {
System.out.println(Arrays.toString(a));
} else {
for (int i = 0; i < n - 1; i++) {
generate(n - 1, a);
if ((n & 1) == 0) {
swap(i, n - 1, a);
} else {
swap(0, n - 1, a);
}
}
generate(n - 1, a);
}
}
public static void swap(int a, int b, int[] array) {
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
I believe the best way to do this is to implement a Spliterator and wrap it in a Stream:
public interface Combinations<T> extends Stream<List<T>> {
public static <T> Stream<List<T>> of(Collection<T> collection) {
SpliteratorSupplier<T> supplier =
new SpliteratorSupplier<T>(collection);
return supplier.stream();
}
...
}
Which solves the general use-case:
Combinations.of(List.of(X, Y, Z)).forEach(t -> process(t));
Implementing the Spliterator is straightforward but tedious and I have written about it here. The key components are a DispatchSpliterator:
private Iterator<Supplier<Spliterator<T>>> spliterators = null;
private Spliterator<T> spliterator = Spliterators.emptySpliterator();
...
protected abstract Iterator<Supplier<Spliterator<T>>> spliterators();
...
#Override
public Spliterator<T> trySplit() {
if (spliterators == null) {
spliterators = Spliterators.iterator(spliterators());
}
return spliterators.hasNext() ? spliterators.next().get() : null;
}
#Override
public boolean tryAdvance(Consumer<? super T> consumer) {
boolean accepted = false;
while (! accepted) {
if (spliterator == null) {
spliterator = trySplit();
}
if (spliterator != null) {
accepted = spliterator.tryAdvance(consumer);
if (! accepted) {
spliterator = null;
}
} else {
break;
}
}
return accepted;
}
A Spliterator for each prefix:
private class ForPrefix extends DispatchSpliterator<List<T>> {
private final int size;
private final List<T> prefix;
private final List<T> remaining;
public ForPrefix(int size, List<T> prefix, List<T> remaining) {
super(binomial(remaining.size(), size),
SpliteratorSupplier.this.characteristics());
this.size = size;
this.prefix = requireNonNull(prefix);
this.remaining = requireNonNull(remaining);
}
#Override
protected Iterator<Supplier<Spliterator<List<T>>>> spliterators() {
List<Supplier<Spliterator<List<T>>>> list = new LinkedList<>();
if (prefix.size() < size) {
for (int i = 0, n = remaining.size(); i < n; i += 1) {
List<T> prefix = new LinkedList<>(this.prefix);
List<T> remaining = new LinkedList<>(this.remaining);
prefix.add(remaining.remove(i));
list.add(() -> new ForPrefix(size, prefix, remaining));
}
} else if (prefix.size() == size) {
list.add(() -> new ForCombination(prefix));
} else {
throw new IllegalStateException();
}
return list.iterator();
}
}
and one for each combination:
private class ForCombination extends DispatchSpliterator<List<T>> {
private final List<T> combination;
public ForCombination(List<T> combination) {
super(1, SpliteratorSupplier.this.characteristics());
this.combination = requireNonNull(combination);
}
#Override
protected Iterator<Supplier<Spliterator<List<T>>>> spliterators() {
Supplier<Spliterator<List<T>>> supplier =
() -> Collections.singleton(combination).spliterator();
return Collections.singleton(supplier).iterator();
}
}

Abstract Data Type implementation in Procedural Programming

I have a question for the more advanced OOP developers here.
I am currently a CS student. We learned a Procedural Programming in Java the first semester where ADT was introduced. I understand the theory and the idea of why ADT is good and what are the benefits of it but it seems quite difficult for me to implement it in code. I get confused and lost.
In addition to that our exit test was on paper (we had to write around 200 line of code on paper) and I found it difficult.
Are there any tips before starting to construct the program?
For instance, do you guys already know how many methods and what method what it will return and have as a formal argument before you start to write the code?
You can approach it programming-style.
First, you need to define an interface for the ADT. Just write down its name and what it does.
Example:
ADT: Integer Stack
void push(int element) - adds an element to the top of stack
int pop() - removes and returns an element from the top of stack
int peek() - returns the value of top. no removal of value
boolean isEmpty() - returns true if the stack is empty
int size() - returns the number of element in the stack.
void print() - print all values of stack
Next is you need to decide on its implementation. Since ADT is about storage, it will be good to decide on storage strategy first.
Example:
ADT: Integer Stack
Implementation: Array Integer Stack
Implements an int stack using Java's built-in array functionality.
Since array is a static collection, i need to use an integer variable to track "top"
When everything is set, you can now proceed to coding.
public interface IntegerStack {
void push(int e);
int pop();
int peek();
boolean isEmpty();
int size();
void print();
}
public class ArrayIntegerStack implements IntegerStack {
private static final int INITIAL_TOP_INDEX = -1;
private int topIndex = INITIAL_TOP_INDEX;
private int[] stackValue = new int[Integer.MAX_VALUE];
#Override
public void push(int element) {
stackValue[++topIndex] = element;
}
#Override
public int pop() {
return stackValue[topIndex--];
}
#Override
public int peek() {
return stackValue[topIndex];
}
#Override
public boolean isEmpty() {
return INITIAL_TOP_INDEX == topIndex;
}
#Override
public int size() {
return topIndex + 1;
}
#Override
public void print() {
for (int i = 0; i <= topIndex; i++) {
System.out.println(stackValue[i]);
}
}
}
Adding on to the answer of KaNa001, you could use a modified HashMap where the key is the index and the value is the integer in the stack. This wont cause an Exception, as the HashMap object can change its length.
public class OrderSet<T> {
private HashMap<Integer, T> array;
public OrderSet() {
array = new HashMap<Integer, T>();
}
public void addAt (T o, int pos) {
// uses Array indexing
HashMap<Integer, T> temp = new HashMap<Integer, T>();
if (!(array.size() == 0)) {
for (int i = 0; i < array.size(); i++) {
temp.put(i, array.get(i));
}
array.put(pos, o);
int size = array.size();
for (int i = pos + 1; i < size + 1; i++) {
array.put(i, temp.get(i - 1));
}
} else {
array.put(0, o);
}
}
public T getPos (int pos) {
if (array.size() == 0) {
return null;
} else {
return array.get(pos);
}
}
}

Java Priority Queue Comparator

I have defined my own compare function for a priority queue, however the compare function needs information of an array. The problem is that when the values of the array changed, it did not affect the compare function. How do I deal with this?
Code example:
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Main {
public static final int INF = 100;
public static int[] F = new int[201];
public static void main(String[] args){
PriorityQueue<Integer> Q = new PriorityQueue<Integer>(201,
new Comparator<Integer>(){
public int compare(Integer a, Integer b){
if (F[a] > F[b]) return 1;
if (F[a] == F[b]) return 0;
return -1;
}
});
Arrays.fill(F, INF);
F[0] = 0; F[1] = 1; F[2] = 2;
for (int i = 0; i < 201; i ++) Q.add(i);
System.out.println(Q.peek()); // Prints 0, because F[0] is the smallest
F[0] = 10;
System.out.println(Q.peek()); // Still prints 0 ... OMG
}
}
So, essentially, you are changing your comparison criteria on the fly, and that's just not the functionality that priority queue contracts offer. Note that this might seem to work on some cases (e.g. a heap might sort some of the items when removing or inserting another item) but since you have no guarantees, it's just not a valid approach.
What you could do is, every time you change your arrays, you get all the elements out, and put them back in. This is of course very expensive ( O(n*log(n))) so you should probably try to work around your design to avoid changing the array values at all.
Your comparator is only getting called when you modify the queue (that is, when you add your items). After that, the queue has no idea something caused the order to change, which is why it remains the same.
It is quite confusing to have a comparator like this. If you have two values, A and B, and A>B at some point, everybody would expect A to stay bigger than B. I think your usage of a priority queue for this problem is wrong.
Use custom implementation of PriorityQueue that uses comparator on peek, not on add:
public class VolatilePriorityQueue <T> extends AbstractQueue <T>
{
private final Comparator <? super T> comparator;
private final List <T> elements = new ArrayList <T> ();
public VolatilePriorityQueue (Comparator <? super T> comparator)
{
this.comparator = comparator;
}
#Override
public boolean offer (T e)
{
return elements.add (e);
}
#Override
public T poll ()
{
if (elements.isEmpty ()) return null;
else return elements.remove (getMinimumIndex ());
}
#Override
public T peek ()
{
if (elements.isEmpty ()) return null;
else return elements.get (getMinimumIndex ());
}
#Override
public Iterator <T> iterator ()
{
return elements.iterator ();
}
#Override
public int size ()
{
return elements.size ();
}
private int getMinimumIndex ()
{
T e = elements.get (0);
int index = 0;
for (int count = elements.size (), i = 1; i < count; i++)
{
T ee = elements.get (i);
if (comparator.compare (e, ee) > 0)
{
e = ee;
index = i;
}
}
return index;
}
}

Categories