Find array if it is subset of another array - java

This function should return true only if the parameter object is a subset of the calling object but it always returns true. How to fix it?
public boolean contains(FileCollection other) {
int i = 0;
int j = 0;
for (i = 0; i<other.files.length; i++) {
for (j = 0; j<this.files.length; j++) {
if ((other.files[i]).equals((this.files[j]))) //this refers to the equals method defined in File class
break;
}
if (j==this.files.length)
return false;
}
return true;//this method is in FileCollection class
}

(Since you didn't explicitly express what the data type of the array elements is, I'll assume it's File, inferred from comments.)
If you don't mind converting between data structures, maybe converting your arrays (temporarily) to Collections is the most simple way. For example, converting to List:
/* #param other
* #return true if the calling object contains
* all files in the parameter object, false otherwise
*/
public boolean contains(FileCollection other) {
List<File> myList = Arrays.asList(this.files);
List<File> otherList = Arrays.asList(other.files);
return myList.containsAll(otherList);
}
Based on your clarify of what to be considered as "contains" when duplicated items are allowed, I'd say you need to count the number of existence for each element. Here is how:
Based on the answer of #Eritrean , you can get and store the count to a map. I made modifications to check the count too:
public boolean contains(FileCollection other) {
Map<File,Integer> otherFrequency = Arrays.stream(other.files)
.collect(Collectors.toMap(Function.identity(), v->1,Integer::sum));
Map<File,Integer> thisFrequency = Arrays.stream(this.files)
.collect(Collectors.toMap(Function.identity(), v->1,Integer::sum));
if (thisFrequency.entrySet().containsAll(otherFrequency).entrySet()) {
for (File entry : otherFrequency.entrySet()) {
if (thisFrequency.get(entry) < otherFrequency.get(entry))
return false;
}
return true;
}
return false;
}

For other.files contains this.files to hold, every this.file must be in other.files.
for (int j = 0; j < this.files.length; j++) {
boolean found = false;
for (int i = 0; i < other.files.length; i++) {
if (other.files[i].equals(this.files[j])) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
Not knowing the class of files, probably you can do:
for (String file : this.files) {
boolean found = false;
for (String otherFile : other.files) {
if (otherFile.equals(file)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
Or even
for (String file : this.files) {
boolean found = other.files.indexOf(file) != -1;
if (!found) {
return false;
}
}
return true;
There are nicer datastructures that speed things up, and have predefined methods for things like contains.
With duplicates
Comparator<File> comparator = new Comparator<File>() {
#Override
public int compare(File lhs, File rhs) {
int cmp = lhs.getBase().compareIgnoreCase(rhs.getBase());
if (cmp == 0) {
cmp = lhs.getExtension().compareIgnoreCase(rhs.getExtension());
}
if (cmp == 0) {
cmp = Long.compare(lhs.getSize(), rhs.getSize());
}
return cmp;
}
};
Arrays.sort(this.files, comparator);
Arrays.sort(other.files, comparator);
int otherI = 0;
for (File file : this.files.length) {
boolean found = false;
while (otherI < other.files.length) {
int comparison = comparator.compare(other.files[otherI], file);
++otherI;
if (comparison >= 0) {
found = comparison == 0;
break;
}
}
if (!found) {
return false;
}
}
return true;
By sorting both arrays you can synchronize the comparison at locations in both arrays. The above handles duplicates.

Apart from the #renyuneyun suggestion to convert your arrays into Lists you could also make use of the String contains method
public boolean contains(FileCollection other) {
String myList = Arrays.toString(this.files);
String otherList = Arrays.toString(other.files);
return myList.contains(otherList);
}
Of course both of these suggestions are not the optimum solutions from the complexity point of view, but are for sure the shortests :)

What about using a map with File as key and frequency as value:
public boolean contains(FileCollection other) {
Map<File,Integer> otherFrequency = Arrays.stream(other.files)
.collect(Collectors.toMap(Function.identity(), v->1,Integer::sum));
Map<File,Integer> thisFrequency = Arrays.stream(this.files)
.collect(Collectors.toMap(Function.identity(), v->1,Integer::sum));
return thisFrequency.entrySet().containsAll(otherFrequency.entrySet());
}

Only this answer works for me: (Credit to #Joop Eggen for the Comparator part)
public boolean contains(FileCollection other) {
Comparator<File> comparator = new Comparator<File>() {
#Override
public int compare(File lhs, File rhs) {
int cmp = lhs.getBase().compareToIgnoreCase(rhs.getBase());
if (cmp == 0) {
cmp = lhs.getExtension().compareToIgnoreCase(rhs.getExtension());
}
if (cmp == 0) {
cmp = Long.compare(lhs.getSize(), rhs.getSize());
}
if (cmp == 0) {
cmp = Long.compare(lhs.getPermissions(), rhs.getPermissions());
}
return cmp;
}
};
Arrays.sort(this.files, comparator);
Arrays.sort(other.files, comparator); //THIS AND THE COMPARATOR SORT THE ARRAYS BASED ON ALL FILE ATTRIBUTES
int i = 0;
int j = 0;
if (this.files.length<other.files.length)
return false;
while (i<other.files.length && j<this.files.length) {
if (!(this.files[j].equals(other.files[i])))
j++;
else {
j++;
i++;
}
}
if (i<other.files.length)
return false;
else
return true;
}

Related

SparseBooleanArray.equals() not working as expected

In the following code I would expect equals() to return true, but it does not. What am I missing here?
SparseBooleanArray array_0 = new SparseBooleanArray();
array_0.put(0, true);
array_0.put(2, true);
SparseBooleanArray array_1 = new SparseBooleanArray();
array_1.put(0, true);
array_1.put(2, true);
boolean isEqual = array_0.equals(array_1); // is false instead of true
Looking at both array in the debugger, they seem the same to me (they have a different shadow$_monitor_ value, but I have no idea what that is supposed to be). The toString() method returns the same string for both as well.
I am trying to write a unit test for a function that converts an EnumSet to a SparseBooleanArray, but I can't create the same array manually to compare it with the function's return value.
Edit
I should also mention that hasCode() returns different values as well, which should not, based on the documentation.
Looking at the source code both the equals and hashCode methods are not implemented for SparseBooleanArray, SparseIntArray, SparseLongArray and SparseArray. I would say this is a critical missing feature and should be reported to Google.
Anyway, I use for quite some time these utility methods to solve this problem:
public static boolean equals(SparseArray arrayOne, SparseArray arrayTwo){
if(arrayOne == arrayTwo){
return true;
} else if(arrayOne.size() != arrayTwo.size()){
return false;
}
for(int i = 0; i < arrayOne.size(); i++){
if(arrayOne.keyAt(i) != arrayTwo.keyAt(i)){
return false;
}
final Object valueOne = arrayOne.valueAt(i);
final Object valueTwo = arrayTwo.valueAt(i);
if(valueOne != null && !valueOne.equals(valueTwo)){
return false;
} else if(valueTwo != null && !valueTwo.equals(valueOne)){
return false;
}
}
return true;
}
public static boolean equals(SparseBooleanArray arrayOne, SparseBooleanArray arrayTwo){
if(arrayOne == arrayTwo){
return true;
} else if(arrayOne.size() != arrayTwo.size()){
return false;
}
for(int i = 0; i < arrayOne.size(); i++){
if(arrayOne.keyAt(i) != arrayTwo.keyAt(i)){
return false;
} else if(arrayOne.valueAt(i) != arrayTwo.valueAt(i)){
return false;
}
}
return true;
}
public static boolean equals(SparseIntArray arrayOne, SparseIntArray arrayTwo){
if(arrayOne == arrayTwo){
return true;
} else if(arrayOne.size() != arrayTwo.size()){
return false;
}
for(int i = 0; i < arrayOne.size(); i++){
if(arrayOne.keyAt(i) != arrayTwo.keyAt(i)){
return false;
} else if(arrayOne.valueAt(i) != arrayTwo.valueAt(i)){
return false;
}
}
return true;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public static boolean equals(SparseLongArray arrayOne, SparseLongArray arrayTwo){
if(arrayOne == arrayTwo){
return true;
} else if(arrayOne.size() != arrayTwo.size()){
return false;
}
for(int i = 0; i < arrayOne.size(); i++){
if(arrayOne.keyAt(i) != arrayTwo.keyAt(i)){
return false;
} else if(arrayOne.valueAt(i) != arrayTwo.valueAt(i)){
return false;
}
}
return true;
}
It is however also possible (as mentioned in the comments), and possibly better, to subclass the SparseArray class and override the equals and hashCode methods.
Disclaimer: I did not test the hashCode or equals implementation of the code provided below, please write some tests yourself to make sure it works correctly. #DontTrustTheInternet
public class SparseBooleanArray extends android.util.SparseBooleanArray {
#Override
public boolean equals(Object o) {
if(!(o instanceof SparseBooleanArray)){
return false;
} else if(this == o){
return true;
}
final SparseBooleanArray other = (SparseBooleanArray) o;
if(size() != other.size()){
return false;
}
for(int i = 0; i < size(); i++){
if(keyAt(i) != other.keyAt(i)){
return false;
} else if(valueAt(i) != other.valueAt(i)){
return false;
}
}
return true;
}
#Override
public int hashCode() {
int result = 17;
for(int i = 0; i < size(); i++){
result = 31 * result + keyAt(i);
result = 31 * result + (valueAt(i)?1:0);
}
return result;
}
}

I need to correct the code to return true if value is in array, otherwise return false. but this code return both of them using (for in) loop

int[] Scores={2,3,8,7,1,4,9};
int kema=7;
boolean T=true;
boolean F=false;
for(int value : Scores)
if(kema == value) {
System.out.println(T);
break;
}
system.out.println(F);
I need to correct the code to return true if value is in array, otherwise return false. but this code return both of them using (for in) loop.
Like the user Jack suggested in the comments to your question. Use a boolean to keep track of if the value was found in the array.
int[] Scores={2,3,8,7,1,4,9};
int kema = 7;
boolean T = true;
boolean F = false;
boolean found = false;
for(int value : Scores) {
if(kema == value) {
found = true;
break;
}
}
if(found) {
System.out.println(T);
} else {
System.out.println(F);
}
You also don't need to have two booleans representing true and false, one boolean is either true or false. So the following could also work:
int[] Scores={2,3,8,7,1,4,9};
int kema = 7;
boolean found = false;
for(int value : Scores) {
if(kema == value) {
found = true;
break;
}
}
System.out.println(found);
In Java 8+ you can use an IntStream1 and something like
System.out.println(IntStream.of(Scores).anyMatch(x -> x == kema));
In earlier versions of Java, you might extract the logic to a method like
public static boolean contains(int[] arr, int val) {
for (int v : arr) {
if (v == val) {
return true;
}
}
return false;
}
And then call it like
System.out.println(contains(Scores, kema));
1Also, by convention, variables should start with lower case letter.

Checking an array for descending order

I am writing code to check if my array is in ascending or descending order. If the boolean 'ascending' is true, then I check if it is ascending. If it is false, then I check for descending. I need help checking whether the array is descending or not... I have the code to check ascending which is written below:
protected boolean isSorted(boolean ascending) {
boolean result = false;
if (ascending) {
for (int i=0;i<data.length-1;i++) {
if(data[i] < data[i+1]) {
result = true;
} else if(data[i] > data[i+1]) {
result = false;
}
}
} else {
//code to check for descending order
}
}
The first part of the if (the "ascending" check) is wrong, it should be:
for (int i = 0; i < data.length-1; i++) {
if (data[i] > data[i+1]) {
return false;
}
}
return true;
Conversely, the descending check should be (and notice that it's enough to change the direction of the comparison operator):
for (int i = 0; i < data.length-1; i++) {
if (data[i] < data[i+1]) {
return false;
}
}
return true;
In both cases, you have to break out of the loop as soon as you find a single pair of numbers that do not hold the ascending-or-descending property, and only return true after the loop exits.
You can cheat and do it in one loop if you like and remove one addition:
protected boolean isSorted(boolean ascending) {
for (int i = 1; i < data.length; i++) {
if (data[i-1] == data[i]) {
continue;
}
if ((data[i-1] > data[i]) == ascending) {
return false;
}
}
return true;
}
NOTE: I am building on the code by #OscarLopez so upvote his if you upvote mine.
To check if ArrayList<Integer> is in descending order try this:
boolean isSorted(ArrayList<Integer> list){
boolean sorted = true;
for (int i = 1; i < list.size(); i++) {
if (list.get(i-1) >= (list.get(i)) ) {
sorted = true;
} else {
return false;
} // if else ends
} // for "i" ends
return sorted;
}

How do I make a return type of int[][] with a for loop?

Heres my code:
public int getPieceCoords(int entityId) {
for(int x = 0;x<8;x++) {
for(int y=0;y<8;y++) {
if(position[x][y] == entityId){
return position[x][y];
}else{
return (int)null;
}
}
}
//Need a return here, but it overrides the returns above
}
So, I am having trouble getting this to return the actual output I want, help is appreciated!
public int getPieceCoords(int entityId) {
int temp = 0;
for(int x = 0;x<8;x++) {
for(int y=0;y<8;y++) {
if(position[x][y] == entityId){
temp = position[x][y];
}
}
}
return temp;
}
Try this ::
public int getPieceCoords(int entityId)
{
int result = -1;
for(int x = 0;x<8;x++)
{
for(int y=0;y<8;y++)
{
if(position[x][y] == entityId)
{
result = position[x][y];
break;
}
}
}
return result;
}
You have specified to return int[][] type in your method but,
return position[x][y];
is returning an int , you might want to check it.
Edit: According to your new(edited) code, you are returning the same value as of parameter
entityId
in case of match or 0 if there is no match.
This doesn't make much sense, why not to use Boolean as return type? i.e return true on match or false otherwise?

Refactoring generic compareTo method

What am I doing:
I have a container class named Os, that can contains different type elements and also instances of class Os. When I compare this class, I want to see :
shallow equals for elements
deep equals for Os elements
I have ensured, that every single element contained in class:
Can not be null.
Is comparable to same type elements.
Is immutable. Well, at least part that I'm checking.
Following is what I have at the moment.
Example:
For example, this test case will pass.
Os o1 = Os.of(3, 4d, Os.of("-"));
Os o2 = Os.of(Os.of(Character.toString('-')), 4.0, new Integer(3));
assertEquals(o1.toString(), "[3, 4.0, [-]]");
assertEquals(o2.toString(), "[[-], 4.0, 3]");
assertTrue(o1.reverse().compareTo(o2) == 0);
Code example:
compareTo method:
#Override
public int compareTo(final Os that) {
final int BEFORE = -1;
final int EQUAL = 0;
final int AFTER = 1;
int subresult = 0;
Comparable<?> othis;
Comparable<?> othat;
if (that == null)
return AFTER;
if (this == that)
return EQUAL;
subresult = ((Integer) this.o.size()).compareTo(that.o.size());
if (subresult < 0)
return BEFORE;
else if (subresult > 0)
return AFTER;
try {
for (int i = 0; i < this.o.size(); i++) {
othis = this.o.get(i);
othat = that.o.get(i);
if (othis.getClass() == othat.getClass()) {
if (othat instanceof Os) {
subresult = ((Os) othis).compareTo(((Os) othat));
if (subresult < 0)
return BEFORE;
else if (subresult > 0)
return AFTER;
} else {
subresult = hackCMP(othis, othat);
if (subresult < 0)
return BEFORE;
else if (subresult > 0)
return AFTER;
}
} else {
subresult = othis.getClass().getName()
.compareTo(othat.getClass().getName());
if (subresult < 0)
return BEFORE;
else if (subresult > 0)
return AFTER;
}
}
return EQUAL;
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return BEFORE;
}
private static int hackCMP(Object val, Object val2)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
Method m = val.getClass().getMethod("compareTo", val.getClass());
return (Integer) m.invoke(val, val2);
}
Question:
I would like to refactor the code.
For example:
I would prefer not using hackCMP method, if possible.
Following code segment seems to repeat itself a lot. Can I replace it with something?
subresult = <expression>;
if (subresult < 0)
return BEFORE;
else if (subresult > 0)
return AFTER;
//else ...
What can I refactor and how to do it?
Edit:
#wolfcastle : Data is stored in private final ImmutableList<Comparable<?>> o;.
I'd like to mention, that every answer was useful. Following seems to work:
#Override
public int compareTo(final Os that) {
Ordering<Iterable<Comparable<?>>> order = //
Ordering.natural().<Comparable<?>> lexicographical();
int result = -1;
try {
result = ComparisonChain.start()
.compare(this.o.size(), that.o.size())
.compare(this.o, that.o, order).result();
} catch (Exception e) { //ignore: type mismatch
}
return result;
}
One option I would consider would be storing the elements in a class that allows them to be compared by class rather than by their compareTo method if they aren't the same class:
private static class Element implements Comparable<Element> {
// raw Comparable allows you to call compareTo
private final Comparable comparable;
Element(Comparable comparable) {
this.comparable = comparable;
}
#Override #SuppressWarnings("unchecked")
public int compareTo(Element o) {
Comparable other = o.comparable;
if(comparable.getClass().isInstance(other)) {
return comparable.compareTo(other);
}
return comparable.getClass().getName().compareTo(other.getClass().getName());
}
#Override
public boolean equals(Object obj) {
return obj instanceof Element && comparable.equals(((Element) obj).comparable);
}
#Override
public int hashCode() {
return comparable.hashCode();
}
#Override
public String toString() {
return comparable.toString();
}
}
Then, with your internal list being a List<Element>, your compareTo method in Os could be pretty simple. Using Guava, it could be extremely simple:
#Override
public int compareTo(Os o) {
return ComparisonChain.start()
.compare(list.size(), o.list.size())
.compare(list, o.list, Ordering.natural().<Element>lexicographical())
.result();
}
You could have a method that returned BEFORE | AFTER | INDETERMINATE (say), then call it.
result = newMethod(subresult);
if (result != INDETERMINATE) return result;
That's not much of an improvement, and it still needs to be duplicated everywhere, but it's a little tighter.
Since the generic type of the List<Comparable<?>> o property is not fixed, I'd get rid of the generic type and rely on the raw type. It costs one #SuppressWarnings("rawtypes"), but it minimizes a lot.
#Override
#SuppressWarnings("rawtypes")
public int compareTo(final Os that) {
final int BEFORE = -1;
final int EQUAL = 0;
final int AFTER = 1;
if (that == null)
return AFTER;
if (this == that)
return EQUAL;
int subresult = ((Integer) this.o.size()).compareTo(that.o.size());
if (subresult != EQUAL)
return subresult;
for (int i = 0; i < this.o.size(); i++) {
Comparable othis = this.o.get(i);
Comparable othat = that.o.get(i);
subresult = othis.compareTo(othat);
if (subresult != EQUAL)
return subresult;
}
return EQUAL;
}

Categories

Resources