I have multiple 2D arrays of Strings that are layed out a little like this
Array 1
[0] = ["01/01/01","Bill","17","0.86"]
[1] = ["02/01/01","Bill","12","0.84"]
[2] = ["03/01/01","Bill","15","0.85"]
Array 2
[0] = ["01/01/01","Joe","14","0.81"]
[1] = ["02/01/01","Joe","15","0.83"]
[2] = ["04/01/01","Joe","19","0.85"]
I'm trying to compare only data from the same days, so what I need to do is search both arrays for dates that are in one but not the other and then remove them. So in the above example I would remove [2] from both of the arrays. Is there a way of doing this using List/Collection retainAll or will I have to write a loop? Oh I'm using Java.
There is no direct way of removing items using collection. But if both the arrays are sorted by date, you would be able to compare the data without removing the missing dates from each of the array.
Well, I don't prefer using arrays for this problem. Removing elements from array is a bad idea. You might try linked list. Something like this
for (int i=0; i < array1List.size(); i++) {
String date = array1List.get(i)[0];
int index = -1;
for(int j=0; j < array2List.size(); j++) {
if array2List.get(j)[0].equals(date)) {
index = j;
break;
}
if(index >= 0) array2List.remove(j);
}
}
To use a Collection to do this you will have to put each array entry into an object. Something like:
class DayInfo {
String date;
String name;
...
public DayInfo(String[] arrayData) {
this.date = arrayData[0];
this.name = arrayData[1];
...
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof DayInfo))
return false;
if (date == null) {
return ((DayInfo)obj).date == null;
} else {
return date.equals((DayInfo)obj).date);
}
}
#Override
public int hashCode() {
if (date == null)
return 0;
else
return date.hashCode();
}
}
Then if you load both of your arrays into DateInfo collections:
Set<DayInfo> dayInfos1 = new HashSet<DayInfo>(array1.length);
for (String[] arrayEntry : array1)
dayInfos1.add(new DayInfo(arrayEntry));
Set<DayInfo> dayInfos2 = new HashSet<DayInfo>(array2.length);
for (String[] arrayEntry : array2)
dayInfos2.add(new DayInfo(arrayEntry));
Now you can use the retainAll in both directions:
// remove everything from set #1 that doesn't have a date in set #2
dayInfos1.retainAll(dayInfos2);
// remove everything from set #2 that doesn't have a date in set #1
dayInfos2.retainAll(dayInfos1);
I think that would work.
Related
I have created a method for my program, where I compare two arrays, user and test. I am trying to add the index of the array user into the ArrayList qMissed when it is not the same as the test Array.
If both arrays are the exact same then it should just return null.
I am getting exception errors because I need to complete the reference type but I am unsure of what to do.
/**
* #param user
* #param test
* #return
*/
public static ArrayList<String> questionMissed(String[] user, String[] test)
{
ArrayList<int> qMissed = new ArrayList<int>();
for (int i = 0; i <= user.length-1; i++)
{
if (user[i] != test[i])
{
qMissed = Arrays.asList(qMissed).indexOf(user);(i+1);
}
else if (user[i] == test[i])
{
return null;
}
}
return qMissed;
}
Your method seems to have some logical and compilation issues.
Looks like you need this method,
public static List<Integer> questionMissed(String[] user, String[] test) {
List<Integer> qMissed = new ArrayList<Integer>();
for (int i = 0; i < user.length; i++) {
if (!user[i].equals(test[i])) {
qMissed.add(i);
}
}
return qMissed.size() == 0 ? null : qMissed;
}
Fixes and their explanation,
1. Your return type has to be List<Integer> instead of ArrayList<String> because you want to return an ArrayList of Integer indexes and not string.
2. Second problem you can't use primitive type in ArrayList<int> instead you need to use ArrayList<Integer>
3. You can't compare strings with == instead you need to use equals method on string.
4. You don't have to return null inside forloop else hence else block I have removed.
5. After you exit the forloop, as you want to return null if both element's arrays matched hence this code,
return qMissed.size() == 0 ? null : qMissed;
Let me know if you face any issues using this method.
Edit:
How to display "All are correct" message in case both passing arrays have same numbers. You must be calling it something like this,
List<Integer> list = questionMissed(user,test);
if (list == null) {
System.out.println("All are correct");
} else {
// your current code
}
You can try changing the return type from ArrayList to ArrayList in the method:
public static ArrayList<int> questionMissed(String[] user, String[] test) {
ArrayList<int> qMissed = new ArrayList<int>();
for (int i=0;i<=user.length-1;i++) {
if (user[i] != test[i]) {
qMissed = Arrays.asList(qMissed).indexOf(user);(i+1);
} else {
return null;
}
}
return qMissed;
}
Also you can remove the else if condition cause is redundant. Please attach the exceptionsyou are getting.
I see multiple issues with your code, Firstly as Andreas said ArrayList cannot host primitive types
so change it to
ArrayList<Integer> qMissed = new ArrayList<Integer>();
Second problem I see is that you are comparing Strings using == this compare can be wrong so use equals instead
(user[i].equals(test[i]))
and the last mistake I see is the code cannot be compiled, can you give me more information in the comments to what you are trying to do in this part since It's not valid code
qMissed = Arrays.asList(qMissed).indexOf(user);
(i + 1);
if you want to do something like Pushpesh Kumar Rajwanshi answer you can use java 8 streams what this does is makes an IntStream with the length of user, and then filters it to have only items if they don't equal at the same index and then adds it to qMissed.
public static List<Integer> questionMissed(String[] user, String[] test) {
List<Integer> qMissed = new ArrayList<>();
IntStream.range(0, user.length)
.filter(i -> !user[i].equals(test[i]))
.forEach(qMissed::add);
return qMissed.size() == 0 ? null : qMissed;
}
I guess you want like below ..
public static ArrayList<Integer> questionMissed(String[] user, String[]
test) {
ArrayList<Integer> qMissed = new ArrayList<Integer>();
int i = 0;
if(user.length == test.length ) {
while(i < user.length ){
if (!(user[i].equals(test[i]))) {
qMissed.add( i + 1);
}else {
return null;
}
i++;
}
if(user.length > 0 && i == user.length ) {
return qMissed;
}
}
return null;
}
how can I sort an Array after deleting one value?
e.g. {1,2,3,4,5} --> {1,2,null,4,5} --> {1,2,4,5,null}.
public boolean removeNumber(int accountNumber) {
for(int i = 0; i < Account.length; i++) {
if(Account[i].getAccountNumber() == (accountNumber)) {
Account[i] = null;
}
Since your original array is already sorted, and assuming that only one Account can have that particular accountNumber, there is no need to sort the array again. Just locate the element to remove, then shift everything after that element down one position, and null out the newly-freed element.
I've renamed the Account field to accounts to follow Java naming conventions, to make a clearer distinction between the array (accounts) and the class (Account), both for the future developers looking at the code, and for the Java compiler.
public boolean removeNumber(int accountNumber) {
for (int i = 0; i < accounts.length; i++) {
if (accounts[i].getAccountNumber() == accountNumber) {
System.arraycopy(accounts, i + 1, accounts, i, accounts.length - i - 1);
accounts[accounts.length - 1] = null;
return true; // Found and removed
}
}
return false; // Not found, so nothing removed
}
Now, if you insist on sorting the array, you can do it like this in Java 8+:
Arrays.sort(accounts, Comparator.nullsLast(Comparator.comparing(Account::getAccountNumber)));
You can follow this way to achieve this :
You need to find the accounts that have the accountNumber you're looking for
you set them to null on the array
You sort the array with a custom Comparator :
if an element is null it has to go at the end
if both are not-null you compare their accountNumber
public boolean removeNumber(int accountNumber) {
for (int i = 0; i < Account.length; i++) {
if (Account[i].getAccountNumber() == accountNumber) {
Account[i] = null;
}
}
Arrays.sort(Account, (o, p) -> {
if (o == null)
return 1;
if (p == null)
return -1;
return Integer.compare(o.getAccountNumber(), p.getAccountNumber());
});
return true;
}
Tips :
follow naming conventions : camelCasefor attriutes ==> Account[] becomes account[]
use .equals() when you are comparing object, for an int == is right
I am facing a problem where I need to sort a String array in alphabetical order. I am able to sort one array, but the problem starts when there are 2 more arrays, that correspond to the first array. Each value in each array should be in the same place, to make information not messed up. After sorting array1, it is in alphabetical order, but i don't have any idea how to make values from array2 and array3 change the positions the same like in array1 after sorting is finished.
My code so far is:
public void sort()
{
boolean finish = false;
while(finish == false){
finish = true;
for(int i=0;i<Country.length-1;i++)
{
int num = 0;
if(Country[i] != null && Country[i + 1] != null)
{
String name1=Country[i]; String name2=Country[i+1];
num=name1.compareTo(name2);
}
else if(Country[i] == null && Country[i + 1] == null){
num = 0;
}
else if(Country[i] == null){
num = 1;
}
else {
num = -1;
}
if(num>0)
{
String temp=Country[i];
Country[i]=Country[i+1];
Country[i+1]=temp;
finish=false;
}
}
}
By far the most recommended way is to re-design your program, and arrange all the related items in a single class. This is what objects are for, after all. Then you can make the object Comparable, give it a compareTo method, and sort it.
But if you are really unable to do that, what you should do is, whenever you exchange any two items in your sort array, make sure you exchange the corresponding items in the other arrays.
So, if you have arrays country, capital and headOfState, you will have to write something like:
String temp=country[i];
country[i]=country[i+1];
country[i+1]=temp;
temp=capital[i];
capital[i]=capital[i+1];
capital[i+1]=temp;
temp=headOfState[i];
headOfState[i]=headOfState[i+1];
headOfState[i+1]=temp;
This way, whenever you move anything in your main array, you'll also be moving the respective item in the other arrays, so they will stay together.
But again, it's much more preferred if you re-designed your program.
Also note the Java language conventions - variable names should not start with a capital letter, only type names should.
If you want all the array to be swaped based on the compare you did in the country array. You can just swap more than one array after one compare.
If(array1[i] > array1[i+1]){
Swap(array1[i],array1[i+1)
Swap(array2[i],array2[i+1])
}
By using a swap function, you can make it more simpler to do swaping in much more array.
You have to swap elements in Country and City arrays simultaneously.
public class BubbleSortTmp {
public String[] Country = {"z", "h", "a"};
public int[] City = {3, 2, 1};
public void printCountry() {
for (String s : Country) {
System.out.printf("%s ", s);
}
System.out.println();
}
public void printCity() {
for (int s : City) {
System.out.printf("%s ", s);
}
System.out.println();
}
public void sort() {
for (int outer = Country.length - 1; outer > 0; outer--) {
for (int inner = 0; inner < outer; inner++) {
if (Country[inner].compareTo(Country[inner+1]) > 0) {
swapCountry(inner, inner+1);
swapCity(inner, inner+1);
}
}
}
}
private void swapCountry(int first, int second) {
String tmp = Country[first];
Country[first] = Country[second];
Country[second] = tmp;
}
private void swapCity(int first, int second) {
int tmp = City[first];
City[first] = City[second];
City[second] = tmp;
}
public static void main(String[] args) {
BubbleSortTmp bs = new BubbleSortTmp();
System.out.println("Before: ");
bs.printCountry();
bs.printCity();
bs.sort();
System.out.println("After: ");
bs.printCountry();
bs.printCity();
}
}
I am trying to check if two arrays have the same length, and the same values in the same exact position.
My current code looks like this:
public class MyArray {
private int size;
private int[] array;
private boolean isSorted; //to check if array is sorted
private static int arrCount; //used to identify which MyArray object
public MyArray(){
size = 10;
array = new int[10];
arrCount+=1;
}
public MyArray(int Size){
size = Size;
array = new int[Size];
arrCount+=1;
}
public MyArray(MyArray arrOther){
this.size = arrOther.getSize();
this.array = arrOther.getArray();
arrCount+=1;
}
public int getSize(){
return size;
}
public int[] getArray(){
return array;
}
#Override
public boolean equals(Object other){
if (other instanceof MyArray){
MyArray second = (MyArray) other;
if (second.getSize() == this.getSize())
return equalsHelper(this.getArray(), second.getArray(), 0, (size-1));
}
//else
return false;
}
private boolean equalsHelper(int[] first, int[] second, int iStart, int iEnd) {
if (iStart == iEnd) {
return true;
}
if (first[iStart] == second[iStart]) {
if (equalsHelper(first, second, (iStart + 1), iEnd)) {
return true;
}
}
return false;
}
}//end class
for some reason it always returns true even if the arrays are in different order.
the equals method is called in the main program here:
--main method--
if (MA2.equals(MA1)) //the arrays are identical here
{
System.out.println("The first and second arrays are equal.");
}
else {System.out.println("The first and second arrays are NOT equal.");}
MA2.sort(); //the order of the elements changes
System.out.println("The second array has been sorted in ascending order.");
if (MA2.equals(MA1))
{
System.out.println("The first and second arrays are equal.");
}
else {System.out.println("The first and second arrays are NOT equal.");}
First check (preferably) outside of your helper should be to see if both the arrays have equal lengths. Makes no sense to continue otherwise.
equalsHelper should return true if end of array is reached.
I see no reason to have 2 separate pointers for index since the arrays are required to be of the same size and the same index is being checked.
Invocation:
....
....
if(first.length != second.length)
return false;
return equalsHelper(first, second, 0);
The helper method...
private boolean equalsHelper(int[] first, int[] second, int indx) {
if(indx == first.length)
return true;
if(first[indx] != second[indx)
return false;
return equalsHelper(first, second, indx+1);
}
Firstly, iStart and iEnd are redundant. use .length
String[] array = new String[10];
int size = array.length;
If you're trying to compare contents of arrays that may be identical, you need to pass through it manually.
for(int i = 0: (i > first.length || i > second.length; i++){
if(first[i] != second[i]){
return false;
}
}
return true
Your next problem is
if (iStart == iEnd){
return first[iEnd] == second[iEnd]; //return true or false
Your logic here is wrong. You can't directly compare arrays like this. It's comparing the memory address. This will always be false unless you pass through the exact same array when the method is called - which i don't think is what you're trying to do
Array lengths are set manually, so it's a conscious effort to get a difference.
Let me suggest using an ArrayList if you're expecting differing lengths. They're also more flexible.
ArrayList <Integer> a = new ArrayList <int>();
ArrayList <Integer> b = new ArrayList <int>();
Then you'll need to check their lengths. ArrayList uses the .length() method instead of an Array[].length property
if(a.length() == b.length()){
then if you want to see if each value in each index is identical, you'll need to pass through the array manually as shown above.
This problem drives me crazy.I have vectorA(float),vectorB(string1),vectorC(string2) which are parallel and i want to eliminate the duplicates in vectorA ,while i manage to retain the
parallelity among the vectors.
Any ideas?
Here's a single-pass, in-place algorithm:
Set<Float> seen = new HashSet<Float>();
int uniques = 0;
for (int i = 0; i < n; i++) {
if (seen.add(vectorA[i])) {
vectorA[uniques] = vectorA[i];
vectorB[uniques] = vectorB[i];
vectorC[uniques] = vectorC[i];
uniques++;
}
}
and then after you're done, ignore all elements after position uniques (or copy them all into new arrays).
Create a set<float> for items that you have seen, scan through vectorA recording duplicate indexes, then delete indexes that you marked as duplicates while going back starting at the end of the vectors.
Set<Float> seen = new HashSet<Float>();
List<Integer> del = new List<Integer>();
for (int i = 0 ; i != vectorA.size() ; i++) {
if (seen.add(vectorA[i])) {
del.add(i);
}
}
for (int i = del.size()-1 ; i >= 0 ; i--) {
vectorA.remove(del[i]);
vectorB.remove(del[i]);
vectorC.remove(del[i]);
}
Going back is important, because otherwise your indexes will get out of sync.
Create a class that combines the three values and overrides equals and hashCode. Add these instances to a single list instead of three parallel lists. Once you're ready to remove duplicates (assuming you need to keep them around first and remove them at a later point), add them to a LinkedHashSet and back to an ArrayList. LinkedHashSet will maintain insertion order (if that's not important use a standard HashSet) while removing duplicates.
class Triple {
float num;
String a;
String b;
public boolean equals(Object o) {
if (o == null || !(o instanceof Triple))
return false;
return num == ((Triple)o).num; // strict equality
}
public int hashCode() {
return Float.floatToRawIntBits(num);
}
}
List<Triple> removeDuplicates(List<Triple> items) {
return new ArrayList<Triple>(new LinkedHashSet<Triple>(items));
}