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.
I have a class called Word in which each instance has String, ArrayList<Character>, and a double. Let's say there are 3 instances of this class. I would like to create a new ArrayList<String> in which all 3 word strings are contained. However, the order of the Strings must go from high to low of the doubles from their original instances. The major stipulation of this project is that the Collections.sort method cannot be used. Please see the code below and let me know if you can think of a way to write this loop (a loop is needed because there is actually +50,000 words):
import java.awt.List;
import java.util.ArrayList;
import java.util.Arrays;
public class WordRecommender {
String fileName;
public WordRecommender(String fileName) {
this.fileName = fileName;
}
public static void main(String[] args) {
ArrayList<Word> objectArray = new ArrayList<Word>();
objectArray.add(new Word("people", null ,0.8));
objectArray.add(new Word("dogs", null ,0.4));
objectArray.add(new Word("cats", null ,0.6));
ArrayList<String> outputArray = new ArrayList<String>();
for (int i = 0; i < finalArray.size(); i++) {
// code here to find the value of each double and place the
// associated strings into output Array from highest to lowest
}
// ideal outputArray order = ["people", "cats", "dogs"]
}
import java.util.ArrayList;
public class Word {
String wordName;
ArrayList<Character> uniqueLetters;
double percent;
public Word(String string, double percent) {
ArrayList<Character> tempArray = new ArrayList<Character>();
for (int i = 0; i < string.length(); i++) {
tempArray.add(string.charAt(i));
}
this.wordName = string;
this.uniqueLetters = tempArray;
this.percent = percent;
}
}
The result you need to achieve can be broken in 2 major steps:
Describing how, giving 2 Words, which of them will be put before the other in the List
Using the comparing method to actually sort your list of Words.
Step 1: How can we decide which word comes first?
Java has an interface called Comparable. The name is pretty self-explanatory. When you implement this interface in your Word class, you are telling Java that instances of this class can be compared against each other.
public class Word implements Comparable<Word>{
When you edit this line in your Word class, your IDE will probably complain about a "missing compareTo() method". The compareTo() method is defined in the Comparable interface and its job is deciding, from 2 instances, which one should be considered "larger" (or in our case, should be put first in the List).
An example of a usage is: "apple".compareTo("banana");. This method call should return a positive number if the first instance ("apple") is "larger", a negative number if the second instance ("banana") is "larger", or zero if both are of the same "value". By the way, the compareTo() method implemented by Strings in Java evaluates instances by alphabetical order.
So let's implement our version of the compareTo() method for our Word class.
#Override
public int compareTo(Word anotherWord) {
if(this.percent > anotherWord.percent) {
return 1;
} else if (this.percent < anotherWord.percent) {
return -1;
} else {
return 0;
}
}
Keep in mind that this implementation returns a positive value if the first instance is greater than the second, and a negative value in the other way around.
Now that we have a way of comparing our Words, we can move on to the sorting part.
Step 2: Sorting algorithms
There are a huge variety of sorting algorithms available on the internet. Some are less efficient, some are easier to implement. You can research some of them here.
For me, the easiest sorting algorithm is called BubbleSort. It is not very efficient, though.
ArrayList<Word> objectArray = new ArrayList<Word>();
objectArray.add(new Word("people", 0.8));
objectArray.add(new Word("dogs", 0.4));
objectArray.add(new Word("cats", 0.6));
for(int i = 0; i < objectArray.size() - 1; i++) {
for(int j = 0; j < objectArray.size() - i - 1; j++) {
// Remember: a compareTo() call returning a negative number
// means that the first instance is smaller than the second.
if(objectArray.get(j).compareTo(objectArray.get(j + 1)) < 0) {
Word auxiliary = objectArray.get(j);
objectArray.set(j, objectArray.get(j + 1));
objectArray.set(j + 1, auxiliary);
}
}
}
These two nested for loops will sort objectArray in descending order of percent.
I implemented a solution that involves a sorting algorithm and usage of java.util.Comparable both.
First, you need to implement Word class with java.util.Comparable so that you can define how to compare Word class in order to determine which one is greater or lower than the other. In this case, it will be the percent field.
public class Word implements Comparable<Word> {
String wordName;
ArrayList<Character> uniqueLetters;
double percent;
public Word(String string, double percent) {
ArrayList<Character> tempArray = new ArrayList<Character>();
for (int i = 0; i < string.length(); i++) {
tempArray.add(string.charAt(i));
}
this.wordName = string;
this.uniqueLetters = tempArray;
this.percent = percent;
}
#Override
public int compareTo(Word o) {
// It is better to delegate to built-in Double compare
// because all we need to compare doubles
return Double.compare(this.percent, o.percent);
}
#Override
public String toString() {
return this.wordName;
}
}
Second, the most important part is to implement a sorting algorithm. It can be challenging to implement them on your own so I suggest study them first.
For my solution it will be a regular implementation of Quick Sort algorithm as follows:
public class QuickSort {
private Word[] array;
public QuickSort(Word... words) {
this.array = words;
}
public Word[] sort(){
this.sort(this.array, 0, this.array.length-1);
return this.array;
}
private void sort(Word[] array, int begin, int end) {
//exit condition
if (begin >= end)
return;
Word pivot = array[end];
int sortIndex = begin;
for (int i = begin; i < end; i++) {
// instead of > we use compareTo to externalize comparison logic
// greater than (>) means we sort in descending order
if (array[i].compareTo(pivot) > 0) {
Word swap = array[sortIndex];
array[sortIndex] = array[i];
array[i] = swap;
sortIndex++;
}
}
//placing pivot to the sort index
Word swap = array[sortIndex];
array[sortIndex] = pivot;
array[end] = swap;
this.sort(array, begin, sortIndex-1);
this.sort(array, sortIndex+1, end);
}
}
Finally, you just use QuickSort helper class to sort your collection of Word and get the sorted output:
public class WordRecommender {
String fileName;
public WordRecommender(String fileName) {
this.fileName = fileName;
}
public static void main(String[] args) {
ArrayList<Word> objectArray = new ArrayList<Word>();
objectArray.add(new Word("people" ,0.8));
objectArray.add(new Word("dogs", 0.4));
objectArray.add(new Word("cats" ,0.6));
QuickSort quickSort = new QuickSort(objectArray.toArray(new Word[]{}));
Word[] sortedWordArray = quickSort.sort();
//output: [people, cats, dogs]
System.out.println(Arrays.asList(sortedWordArray));
}
}
I am doing a Java class and I cannot figure it out where I am wrong.
I have a class called ArrayMethods and a method that I must use to see if my arrays are sorted or not. This is my code:
public class ArrayMethods
{
String[] list; //instance variable
/**
* Constructor for objects of class ArrayMethods
*/
public ArrayMethods(String[] list)
{
// initialise instance variables
this.list = list;
}
/**
* Determines if the array is sorted (do not sort)
* When Strings are sorted, they are in alphabetical order
* Use the compareTo method to determine which string comes first
* You can look at the String compareTo method in the Java API
* #return true if the array is sorted else false.
*/
public boolean isSorted()
{
boolean sorted = true;
// TODO: Write the code to loop through the array and determine that each
// successive element is larger than the one before it
for (int i = 0; i < list.length - 1; i++){
if (list[i].compareTo(list[i + 1]) < 0){
sorted = true;
}
}
return sorted;
}
}
And then I have a tester for this arrays that goes like this:
public class ArrayMethodsTester {
public static void main(String[] args) {
//set up
String[] animals = {"ape", "dog", "zebra"};
ArrayMethods zoo = new ArrayMethods(animals);
//test isSorted
System.out.println(zoo.isSorted());
System.out.println("Expected: true");
String[] animals2 = {"ape", "dog", "zebra", "cat"};
zoo = new ArrayMethods(animals2);
System.out.println(zoo.isSorted());
System.out.println("Expected: false");
String[] animals3 = {"cat", "ape", "dog", "zebra"};
zoo = new ArrayMethods(animals3); ;
System.out.println(zoo.isSorted());
System.out.println("Expected: false");
}
}
For the first array I do get true as it is normal, the problem is that I get true for the other 2 and it is clearly that this is false. What is it that I do not get?
could make it a little simpler by directly returning false inside of the loop
for (int i = 0; i < list.length - 1; i++) {
if (list[i].compareTo(list[i + 1]) > 0) {
return false;
}
}
return true;
public class ArrayMethods
{
String[] list; //instance variable
/**
* Constructor for objects of class ArrayMethods
*/
public ArrayMethods(String[] list)
{
// initialise instance variables
this.list = list;
}
/**
* Determines if the array is sorted (do not sort)
* When Strings are sorted, they are in alphabetical order
* Use the compareTo method to determine which string comes first
* You can look at the String compareTo method in the Java API
* #return true if the array is sorted else false.
*/
public boolean isSorted()
{
boolean sorted = true;
// TODO: Write the code to loop through the array and determine that each
// successive element is larger than the one before it
for (int i = 0; i < list.length - 1; i++){
if (list[i].compareTo(list[i + 1]) > 0){
sorted = false;
break;
}
}
return sorted;
}
}`
You could also do it with Java 8 streams if you like their syntax (though it is not a perfect use case for them because you need two elements of the stream for your operation):
public static boolean isSorted(final String[] array) {
return !IntStream.range(1, array.length)
.mapToObj(i -> new Pair<String>(array[i - 1], array[i])).parallel()
.anyMatch(t -> t.first.compareTo(t.second) > 0);
}
The code uses a small helper class Pair
public static final class Pair<T> {
final T first;
final T second;
private Pair(final T first, final T second) {
this.first = first;
this.second = second;
}
}
This solution could also run parallel which would make it faster when running on large arrays.
Credits to Collect successive pairs from a stream for accessing a Pair of elements with streams
I am building a data structure to learn more about java. I understand this program might be useless.
Here's what I want. I want to create a data structure that store smallest 3 values. if value is high, then ignore it. When storing values than I also want to put them in correct place so I don't have to sort them later. I can enter values by calling the add method.
so let's say I want to add 20, 10, 40, 30 than the result will be [10,20,30]. note I can only hold 3 smallest values and it store them as I place them.
I also understand that there are a lot of better ways for doing this but again this is just for learning purposes.
Question: I need help creating add method. I wrote some code but I am getting stuck with add method. Please help.
My Thinking: we might have to use a Iterator in add method?
public class MyJavaApp {
public static void main(String[] args){
MyClass<Integer> m = new MyClass<Integer>(3);
m.add(10);
m.add(20);
m.add(30);
m.add(40);
}
}
public class MyClass<V extends Comparable<V>> {
private V v[];
public MyClass(int s){
this.v = (V[])new Object[s];
}
public void add(V a){
}
}
Here is a rough sketch of the add method you have to implement.
You have to use the appropriate implementation of the compareTo method when comparing elements.
public void add(V a){
V temp = null;
if(a.compareTo( v[0]) == -1 ){
/*
keeping the v[0] in a temp variable since, v[0] could be the second
smallest value or the third smallest value.
Therefore call add method again to assign it to the correct
position.
*/
temp = v[0];
v[0] = a;
add(temp);
}else if(a.compareTo(v[0]) == 1 && a.compareTo(v[1]) == -1){
temp = v[1];
v[1] = a;
add(temp);
}else if(a.compareTo(v[1]) == 1 && a.compareTo(v[2]) == -1){
temp = v[2];
v[2] = a;
add(temp);
}
}
Therefore the v array will contain the lowerest elements.
Hope this helps.
A naive, inefficient approach would be (as you suggest) to iterate through the values and add / remove based on what you find:
public void add(Integer a)
{
// If fewer than 3 elements in the list, add and we're done.
if (m.size() < 3)
{
m.add(a);
return;
}
// If there's 3 elements, find the maximum.
int max = Integer.MIN_VALUE;
int index = -1;
for (int i=0; i<3; i++) {
int v = m.get(i);
if (v > max) {
max = v;
index = i;
}
}
// If a is less than the max, we need to add it and remove the existing max.
if (a < max) {
m.remove(index);
m.add(a);
}
}
Note: this has been written for Integer, not a generic type V. You'll need to generalise. It also doesn't keep the list sorted - another of your requirements.
Here's an implementation of that algorithm. It consists of looking for the right place to insert. Then it can be optimized for your requirements:
Don't bother looking past the size you want
Don't add more items than necessary
Here's the code. I added the toString() method for convenience. Only the add() method is interesting. Also this implementation is a bit more flexible as it respects the size you give to the constructor and doesn't assume 3.
I used a List rather than an array because it makes dealing with generics a lot easier. You'll find that using an array of generics makes using your class a bit more ugly (i.e. you have to deal with type erasure by providing a Class<V>).
import java.util.*;
public class MyClass<V extends Comparable<V>> {
private int s;
private List<V> v;
public MyClass(int s) {
this.s = s;
this.v = new ArrayList<V>(s);
}
public void add(V a) {
int i=0;
int l = v.size();
// Find the right index
while(i<l && v.get(i).compareTo(a) < 0) i++;
if(i<s) {
v.add(i, a);
// Truncate the list to make sure we don't store more values than needed
if(v.size() > s) v.remove(v.size()-1);
}
}
public String toString() {
StringBuilder result = new StringBuilder();
for(V item : v) {
result.append(item).append(',');
}
return result.toString();
}
}