I want to check to see if two arrays share at least one term in common for my program.
I'm not quite sure what the code is to compare two arrays, but here is what I have so far;
if ((modWikiKeyArray).equals(inputArray[0]))
{
StringBuilder hyperlinkBuilder = new StringBuilder();
for(int i = 0; i < modWikiKeyArray.length; i++)
{
hyperlinkBuilder.append(modWikiKeyArray[i]);
}
}
How would I compare the array modWikiKeyArray to inputArray just to check and see if inputArray[0] is equal to any term inside of modWikiKeyArray?
Arrays.asList lets you build a list backed by an arbitrary array and use convenient Java Collections Framework features like the contains method:
Arrays.asList(oneArray).contains(elementFromAnotherArray)
If you want to see if the arrays have at least one element in common, you could build a HashSet out of one and loop over the other to try to find a common element:
boolean arraysIntersect(Object[] array1, Object[] array2) {
Set array1AsSet = HashSet(Arrays.asList(array1));
for (Object o : array2) {
if (array1AsSet.contains(o)) {
return true;
}
}
return false;
}
You can do the following
for(int i=0;i<modWikiKeyArray.length;i++) {
if(modWikiKeyArray[i].equals(inputArray[0])) {
System.out.println("Match found");
}
}
Note you need to override the equals() method of whatever array you are creating(Class of which array you are creating) .
Going by your code snippet, it looks like you need to check the presence of inputArray[0] only, in which case the following is sufficient:
boolean exists = java.util.Arrays.asList(modWikiKeyArray).contains(inputArray[0]);
Alternatively, you might also want to use ArrayUtils from Apache commons-lang:
boolean exists = ArrayUtils.contains(modWikiKeyArray, inputArray[0]);
However, if I read the text of your question, it seems you want to find if modWikiKeyArray contains at least one item from inputArray. For this you may also use retainAll from the Collections API to perform a list intersecion and see if the intersection list is non-empty.
However, the most primitive is still Aniket's method. However, I will modify it to reduce unnecessary operations:
int i = modWikiKeyArray.length - 1;
MyObject inputElement = inputArray[0];
boolean found = false;
for(; i != 0; i--) {
if(modWikiKeyArray[i].equals(inputElement)) {
found = true;
break;
}
}
Related
I was trying to write some functional programming code (using lambdas and streams from Java 8) to test if a string has unique characters in it (if it does, return true, if it does not, return false). A common way to do this using vanilla Java is with a data structure like a set, i.e.:
public static boolean oldSchoolMethod(String str) {
Set<String> set = new HashSet<>();
for(int i=0; i<str.length(); i++) {
if(!set.add(str.charAt(i) + "")) return false;
}
return true;
}
The set returns true if the character/object can be added to the set (because it did not exist there previously). It returns false if it cannot (it exists in the set already, duplicated value, and cannot be added). This makes it easy to break out the loop and detect if you have a duplicate, without needing to iterate through all length N characters of the string.
I know in Java 8 streams you cannot break out a stream. Is there anyway way to capture the return value of an intermediate stream operation, like adding to the set's return value (true or false) and send that value to the next stage of the pipeline (another intermediate operation or terminal stream operation)? i.e.
Arrays.stream(myInputString.split(""))
.forEach( i -> {
set.add(i) // need to capture whether this returns "true" or "false" and use that value later in
// the pipeline or is this bad/not possible?
});
One of the other ways I thought of solving this problem, is to just use distinct() and collect the results into a new string and if it is the same length as the original string, than you know it is unique, else if there are different lengths, some characters got filtered out for not being distinct, thus you know it is not unique when comparing lengths. The only issue I see here is that you have to iterate through all length N chars of the string, where the "old school" method best-case scenario could be done in almost constant time O(1), since it is breaking out the loop and returning as soon as it finds 1 duplicated character:
public static boolean java8StreamMethod(String str) {
String result = Arrays.stream(str.split(""))
.distinct()
.collect(Collectors.joining());
return result.length() == str.length();
}
Your solutions are all performing unnecessary string operations.
E.g. instead of using a Set<String>, you can use a Set<Character>:
public static boolean betterOldSchoolMethod(String str) {
Set<Character> set = new HashSet<>();
for(int i=0; i<str.length(); i++) {
if(!set.add(str.charAt(i))) return false;
}
return true;
}
But even the boxing from char to Character is avoidable.
public static boolean evenBetterOldSchoolMethod(String str) {
BitSet set = new BitSet();
for(int i=0; i<str.length(); i++) {
if(set.get(str.charAt(i))) return false;
set.set(str.charAt(i));
}
return true;
}
Likewise, for the Stream variant, you can use str.chars() instead of Arrays.stream(str.split("")). Further, you can use count() instead of collecting all elements to a string via collect(Collectors.joining()), just to call length() on it.
Fixing both issues yields the solution:
public static boolean newMethod(String str) {
return str.chars().distinct().count() == str.length();
}
This is simple, but lacks short-circuiting. Further, the performance characteristics of distinct() are implementation-dependent. In OpenJDK, it uses an ordinary HashSet under the hood, rather than BitSet or such alike.
This code might work for you:
public class Test {
public static void main(String[] args) {
String myInputString = "hellowrd";
HashSet<String> set = new HashSet<>();
Optional<String> duplicateChar =Arrays.stream(myInputString.split("")).
filter(num-> !set.add(num)).findFirst();
if(duplicateChar.isPresent()){
System.out.println("Not unique");
}else{
System.out.println("Unique");
}
}
}
Here using findFirst() I am able to find the first duplicate element. So that we don't need to continue on iterating rest of the characters.
What about just mapping to a boolean?
Arrays.stream(myInputString.split(""))
.map(set::add)
.<...>
That would solve your concrete issue, I guess, but it's not a very nice solution because the closures in stream chains should not have side-effects (that is exactly the point of functional programming...).
Sometimes the classic for-loop is still the better choice for certain problems ;-)
I've been developing a small application for work, and I've come across something I can't figure out.
In the following code, I have an ArrayList of a Custom Class called 'Product' that contains data of type 'String'. I use the .contains method on this ArrayList to ensure it doesn't contain a certain String.
My IDE gives me the warning of 'Suspicious call to java.util.Collections.contains: Given object cannot contain instances of String (expected Product)'.
I completely understand the above message, because I'm comparing two different Types, so how can it ever evaluate correctly? I'm thinking it must be because the 'Product' class contains the data I want to compare, it is defaulting to using the toString method on the Product class (I override this in the Class) and comparing it with the String I want to compare it against.
It seems like JVM black magic to me.
private void createOrderListing(List<String[]> orderList)
{
//For each line of the order list file
for(String[] s : orderList)
{
if(s.length >= 28) //OrderLine should be of this length
{
if (!s[0].equalsIgnoreCase("ProductCode") && !s[0].isEmpty()) //Makes sure we're not including headers
{
//How does this bit work?
if(!productListing.contains(s[0]))
{
OrderLine order = new OrderLine();
//References product code of Product against Order Line, if match, then pack sizes and other basic fields ammended as appropriate
boolean productFound = false;
for (Product p : productListing)
{
if (s[0].contentEquals(p.getProductCode()))
{
order.initialAmendOrderLine(p.getProductCode(), p.getProductName(), p.getPackSize(), p.getProductType());
productFound = true;
}
}
if(productFound)
{
order.setOrderValues(s);
orderListing.add(order);
}
}
//System.out.println("\nOrder Product is: " + order.getProductName()+ "\nOrder Pack Size is: " + order.getInternalPackSize());
}
}
}
}
UPDATE
The reason this works as pointed out in the comments is that the block is always true (the .contains method is always false, the ! inverses this, hence true). Sorry for the confusion and pointing out my carelessness.
Here is an implementation of contains method in ArrayList that I have in OpenJDK:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
Basically, there is nothing complex in it. It iterates through the all elements of your ArrayList and checks whether your given object is equal to the current one. If the condition is true then element exists in the list.
So let's imagine that you are passing String "SomeValue" to this method. Elements of ArrayList are iterated and following action is executed: "SomeValue".equals(elementData[i]) where elementData[i] is a product.
Since equals method of String class cannot compare String with a Product it returns false and as a result, you get false from contains method.
To fix this situation you can iterate over ArrayList manually and compare some Product's field with your string. E.g. you can implement following contains method:
public boolean contains(List<Product> products, String yourStringValue) {
for (Product p : products) {
if(p.getProductCode().equals(yourStringValue)){
return true;
}
}
return false;
}
productListing is a list of Product objects. Yet you are asking the list if it contains a specific String object -- which shouldn't ever happen.
What you should do is check if your Product#getProductCode is equal to your specific String. This can be acheived by using streams:
if(!productListing.contains(s[0])) // replace this
// with this
if (!productListing.stream().filter(o -> o.getProductCode().equals(s[0])).findFirst().isPresent())
What does this code do? It checks all your Product elements to find one whose myStringData attribute is equal to the String you're comparing.
since contains relays on equals implementation, when you do
if(!productListing.contains(s[0]))
you are asking the list OF ARRAYS OF STRINGS if its contains a String.
that will return always false because the type are different, so is not that is working at all, is that your condition will always return false
We have a Final exam that is coming up, it is proctored this is just a study question, but I am having issues with two arrays I wrote out when I put them into eclipse. I would like some insight that may help me on the test, thanks.
Write a Java function that accepts two one-dimensional arrays of integers and returns true if and only if all the integers in the first array are contained in the second, and all the integers in the second array are contained in the first
public class Two1dimensionalArraysMain
{
public boolean main(int []array1, int []array2)
{
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
if(array1[i]==array2[j])
{
break;
}
else if (array1[i] != array2[j])
return false;
}
return true;
}
}
}
The problem is that you're returning false too early.
Here's what it looks like you're trying to do. You look at each element X in array1. Then you compare that one element to each element in array2. If X equals any element in array2, you're good (so far) and you can look at the next element in array1. But if X is different from every element in array2, then return false.
That's a good approach. The problem is that you return false if X is different from any element in array2, not if it's different from every element. This is because as soon as you see two elements that are different between the two arrays, you return false right away.
public boolean main(int []array1, int []array2)
{
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
if(array1[i]==array2[j])
{
break;
}
else if (array1[i] != array2[j])
return false;
}
return true;
}
}
To fix this: You need to do the return false check outside the for (int j... loop. There are a number of ways to do this, but my favorite is this:
Declare a boolean variable found. You will initialize this to false before going through array2.
Before you break, set found = true;, to indicate that the element X in array1 was found in array2.
After you're done going through array2, check found. If it's false, then you know the whole function should return false.
Also, your return true is in the wrong place. If you fix those two things, your method should work.
EDIT: I missed that the equality has to be two ways. The above, with my suggestions, will return true if every element in array1 is in array2, but not vice versa. One simple update would be to write a helper method allElementsAreIn that uses two int[] arrays, and then call it twice, something like allElementsAreIn(array1,array2) && allElementsAreIn(array2,array1).
By the way, don't call your function main. That name should be used only for the main program, which must be void and take a String[] parameter.
P.S. I'm assuming that the purpose of the exercise is to learn the basics of loops and such. In an actual production environment, it would be much simpler to use a Set as in amit's answer.
Best solution in my opinion is to use set equality, if that's allowed.
public static boolean checkArraysContainSameElements(int[] array1, int[] array2) {
Set<Integer> set1 = new HashSet<Integer>();
for (int x : array1) set1.add(x);
Set<Integer> set2 = new HashSet<Integer>();
for (int x : array2) set2.add(x);
return set1.equals(set2);
}
Other than that, I refer to #ajb to see what's wrong with the solution you proposed.
You can sort the array and compare in the loop:
public boolean checkArrayEquality(int[] source, int[] target)
{
Arrays.sort(source);
Arrays.sort(target);
if(source.length == target.length)
{
for (int i = 0; i < target.length; i++)
{
if(source[i] != target[i])
{
return false;
}
}
}
else
{
return false;
}
return true;
}
In my Java program's constructor I have the following:
thirdRow.add(button);
button.setActionCommand("Sumbit");
button.addActionListener(this);
And here is the corresponding actionPerformed method that's supposed to take 3 values from some textfields and store them into arrays:
public void actionPerformed(ActionEvent e)
{
String arg = e.getActionCommand();
if (arg == "Submit")
{
//enlarge arrays
qtyStr = enlargeArray(qtyStr);
typeStr = enlargeArray(typeStr);
colorStr = enlargeArray(colorStr);
//add from textfields into current
qtyStr[qtyStr.length-1] = qty.getText();
typeStr[typeStr.length-1] = type.getText();
colorStr[colorStr.length-1] = color.getText();
}
}
//method to enlarge an array by 1
public String[] enlargeArray(String[] currentArray)
{
String[] newArray = new String[currentArray.length + 1];
for (int i = 0; i<currentArray.length; i++)
newArray[i] = currentArray[i];
return newArray;
}
When I run the application, populate the textfields, and click the submit button nothing happens. How can I verify that my string arrays are being appended like they're supposed to?
You've a problem here: if (arg == "Submit")
Don't compare Strings using ==. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two objects are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of
if (fu == "bar") {
// do something
}
do,
if ("bar".equals(fu)) {
// do something
}
or,
if ("bar".equalsIgnoreCase(fu)) {
// do something
}
Also, for safety's sake, I try to use String constants wherever possible so as not to be tripped up by misspellings.
If you want to do your code this way, I would probably do two things:
1) maintain index fields for each array for the next free index, and
2) I wouldn't recommend resizing your array by 1 each time, as our current code is running through the array 2 n times (n = array length), 1st to initialize the array, and 2nd to create a new array.
Two options to optimize thisL one would be be to look into the Arrays class. it contains methods such as Array.copyOf() that can perhaps be useful here. You could also check if the array is full, and if it is then resize it by a number greater than one to reduce extra work.
For instance:
import java.util.Arrays;
class Test{
private String[] a;
private int next;
public Test(int size){
a = new String[size];
next = 0;
}
public void add(String s){
if(next == a.length){
Arrays.copyOf(a, a.length+1);
}
a[next] = s;
next++;
}
}
The easiest way would be to use an ArrayList (or any class that implements the java.util.List interface), as previously mentioned by Jon Skeet - it will do all the work for you.
I am trying to add some data to vector by checking if the vector already has the data,even if vector has the data the loop is coming to else block.
Vector object = (Vector) listUserEvents.get(key);
Vector compareEventData = (Vector) hCompareTable.get(compareKey);
for (int i = 0; i < compareEventData.size(); i++) {
EventData eCompare = (EventData) compareEventData.elementAt(i);
if (object.contains(eCompare)) {
System.out.println("in if of compare");
} else {
System.out.println("in else of compare");
}
If the code is not behaving as you expect, it is most likely that you don't understand what contains is actually doing.
The contains method is looking for an element in the vector which the equals method says is equal to the argument; e.g. it is (more or less) equivalent to:
boolean found = false;
for (Object eventData : object) {
if (eventData.equals(eCompare)) {
found = true;
}
}
If this is giving an unexpected answer, then the likely cause is in the way that equals is defined (or not) for the EventData. In particular, if you haven't overriden equals, then EventData could be inheriting the equals method from Object. If it does that, then equals means "has the same object reference". That is probably the wrong semantic for your use-case.
You need to override EventData.equals(). Once you do this, you should also override hashCode().
Finally, using a Vector results in pretty poor computational complexity since every contains() check costs O(n). Also, using Vector is usually not recommended in new code.
You would be better off using LinkedHashSet instead (or, if the ordering of elements is not important, any Set).
As discussed in the comments, your EventData seem to be different instances in both vectors. If you expect them to be equal in the sense that they contain the same information, you should compare the EventData objects based on a property that is identifying them. E.g.:
Vector<EventData> object = (Vector<EventData>) listUserEvents.get(key);
Vector<EventData> compareEventData = (Vector<EventData>) hCompareTable.get(compareKey);
for (EventData eCompare : compareEventData) {
boolean found = false;
for (EventData other : object) {
if (other.getSomeProperty().equals(eCompare.getSomeProperty())) {
found = true;
break;
}
}
if(found){
System.out.println("contains");
}else {
System.out.println("does not contain");
}
}