So I have a text file that contains a bunch of strings that I import into the program and what my program does is look for the first index of the first duplicate string:
static final int NOT_FOUND = -1;
dupeIndex = indexOfFirstDupe( wordList, wordCount );
if ( dupeIndex == NOT_FOUND )
System.out.format("No duplicate values found in wordList\n");
else
System.out.format("First duplicate value in wordList found at index %d\n",dupeIndex);
and the method I use to find the first index of the duplicate is as follows:
static int indexOfFirstDupe( String[] arr, int count )
{
Arrays.sort(arr);
int size = arr.length;
int index = NOT_FOUND;
for (int x = 0; x < size; x++) {
for (int y = x + 1; y < size; y++) {
if (arr[x].equals(arr[y])) {
index = x;
break;
}
}
}
return index;
The problem is that I get this error:
It's a NullPointerException and from my understanding it means that there's basically a null value(s) in my array of strings(?). Is there any simple solution to this that I am missing? Possibly rewording my method?
The error is caused by Array.sort(arr);
According to Java doc (https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#sort-java.lang.Object%3aA-):
Sorts the specified array of objects into ascending order, according to the natural ordering of its elements. All elements in the array must implement the Comparable interface.
It is very likely that the exception was thrown when the sort tries to call the compareTo method on the null objects of the String array.
So one simple direct solution is to make sure no null objects in your String array...
There is a better way to do what you want to do.
This is complexity O(n) vs yours is O(n^2) + failing sort.
public int indexOfFirstDup(String[] arr) {
Set<String> valuesFound = new HashSet<>();
for (int i=0;i<arr.length; i++) {
String s = arr[i];
// ignore nulls
if (s == null) { continue; }
if (valuesFound.contains(s)) {
// here we identified a duplication and we can leave
return i;
} else {
valuesFound.add(s);
}
}
// no dups
return -1;
}
NOTE the code has not been compiled nor tested - its just an idea!
Assuming that you are correct in your diagnosis
... it means that there's basically a null value(s) in my array of strings ...
... I can think of two workarounds.
Get rid of the null references in the array. Remove them entirely, or replace them with (say) "" or "null" or something else harmless.
There is an overload of the Arrays.sort method that takes a second argument: a Comparator. So what you could do is to implement a Comparator that can handle null without throwing an NPE. (For example, it could treat null as smaller than all non-null strings.)
Here's an example comparator that deals with null:
public class NullSafeStringComparator implements Comparator<String> {
public int compare(String s1, String s2) {
if (s1 == s2) {
return 0;
} else if (s1 == null) {
return -1;
} else if (s2 == null) {
return 1;
} else {
return s1.compareTo(s2);
}
}
}
Alternatively, for Java 8 and later you can build one as follows:
Comparator.nullsFirst(Comparator.naturalOrder())
Related
Pretty much what the title said. I thought of using Sets and comparing sizes with the normal array but then if I had 2 elements with duplicates the Set size would be the same as having one element with 2 duplicates.
Any help on how to approach this would be much appreciated!
I think the fastest approach is the brute force one, i.e. traversing the array and count what you want to count. Each other implementation which you can call by a one liner must traverse the array as well, using a HashMap adds the overhead to fill and maintain the map, and you cannot stop iterating if you have found what you searched for.
With following private method you can use it also by a one liner call from your main code:
main()
{
String[] myArray = new String[] {
"Hello",
"Hello",
"Hello",
null,
null,
};
boolean gotIt = hasAtLeastThreeOccurences( myArray, "Hello");
myLog.debug( "gotIt: " + gotIt );
}
private <T> boolean hasAtLeastThreeOccurences( T[] aArray, T aValue)
{
int count = 0;
boolean isNull = (aValue == null);
for ( T t : aArray )
{
if ( isNull )
{
if ( t == null )
{
count++;
}
}
else
{
if ( aValue.equals( t ) )
{
count++;
}
}
if ( count >= 3 )
{
return true;
}
}
return false;
}
Assuming your array is a String Array (just as an example), you can call this method, if it return null then there is no 3 elements or more with the same value, else it will return the first element found 3 times or more
public String getRedundantItem(String... myArray) {
// Convert the array to List
ArrayList<String> myList = new ArrayList<String>(Arrays.asList(myArray));
// Look for the element which frequency is three or more
for (String item : myList) {
if (Collections.frequency(myList, item) > 2) {
return item;
}
}
// No element more than 2 times
return null;
}
Test Example:
public void test(){
String[] someData = {"stack","over", "flow", "stack", "stack"};
String[] otherData = {"stack","over", "flow", "stack", "flow"};
System.out.println(getRedundantItem(someData)); // prints stack
System.out.println(getRedundantItem(otherData)); // prints null
}
If an array have three elements with same value
we keep : element => number of occurence. difficult to do less or faster
List<String> array=Arrays.asList(new String[] {"aa","bb","cc","aa","bb","dd"}); // Complete with other tests
Iterator<String> it=array.iterator();
// Keep element => occurences
Map<String,Integer> occurences=new HashMap<String,Integer>();
while (it.hasNext())
{
String one_string=it.next();
if (occurences.containsKey(one_string))
{
int how_many=occurences.get(one_string);
if (how_many==2) return true;
// IF NOT
occurences.put(one_string, how_many+1);
}
else // NEW
occurences.put(one_string, 1);
}
// finally
return false;
This is an example using int variables, but the basic idea is that the value to be compared to the other values of the array is set to the first variable. Then as we find elements equal to the key, we increment a temporary count variable. If the temporary count variable is greater than the real count variable, then the real count variable is replaced by the temporary count variable. Once an unequal element is found, a new key value is set to the current element being iterated on and the temporary count variable is reset. This could be tinkered with, however, for example you can break out of the loop once the the temporary count reaches three. I'm not sure if this was what you were looking for, but enjoy.
int key = arr[0];
int tempCount = 0;
int realCount = 0;
for(int i = 1; i < arr.length; i++){
if(arr[i] == key){
tempCount++;
}
else{
key = arr[i];
tempCount = 0;
}
if(tempCount > realCount){
realCount = tempCount;
}
}
if(realCount >= 3){
boolean hasThreeOfTheSame = true;
//do stuff you want to do
}
EDIT: I now realize that the OP wanted a way to find if there were 3 of the same elements in an array despite the order. I misread this so my solution finds whether an array has 3 or more consecutive elements in a row (ex: [1, 1, 1, 2, 3] or [1, 2, 2, 2, 3]). I'm only going to keep this up because it may help someone out there.
My professor have given me a challenging homework, where the idea is to rewrite all the methods in the String classes without using String, StringBuilder, and Wrapper classes. This is for Intro to Java class. I already have some methods done but having a hard time with some other ones. This is for the main class only with no creation of any string inside.
What I have: a "data" as a char[] data for my "MyOwnString" object.
CompareTo method:
public int compareTo(MyOwnString rhs){
if (this.data == rhs.data){
return 0;
} else if (this.data > rhs.data){
return 1;
}
else {
return -1;
}
}
This one shows an error. My guess is that the rhs needs to be declare before being able to compare to any string being assigned to a MyOwnString object.
Since there is a compareTo method and a compareToIgnoreCase, then I would have to add a line to ignore the comparsion?
Update:
This is the code I went with for the compareTo method by creating own method using length of the array.
public int compareTo(MyOwnString cts){
int word1 = data.length;
int word2 = cts.length();
int result = 0;
for (int i=0; i<word1; i++){
for (int j=0;j<word2; j++){
if(word1 == word2){
result = 0;
}
else if (word1 > word2){
result = 1;
}
else {
result = -1;
}
}
}
return result;
}
Since you are not allowed to use String.compareTo()
and since java doesn't support > for your custom objects or char[] for that matter (e.g doesn't support operator overloading) you have to do it programmatically.
In other words you have the two char arrays and you have to loop through all the characters. You compare the first two characters from each of the char arrays (there you can use > or <) if they are == you compare the second two characters and so on.. till you find two characters that break the tie - you can then break your for loop and return the result as -1, 1. If they are tied on every character you return 0.
If you want to implement equals you could just call compareTo and optimize it a bit by checking the lengths of the strings. If they are different then of course the strings are not equal
Update: I am not sure if you ran your code above - try to compile your code and run it before you move forward. I believe it won't even compile.
Here is, I believe, a correct unchecked version. I could have mixed the -1 and 1s as always..
public int compareTo(MyOwnString cts){
int word1Length = ((MyOwnString)this).data.length;
int word2Length = cts.data.length;
for (int i=0; i < Math.min(word1Length,word2Length); i++){
if(this.data[i] == cts.data[i]){
continue;
}
else if (this.data[i] > cts.cts[i]){
return -1;
}
else if (this.data[i] < cts.cts[i]) {
return 1;
}
}
if (word1Length == word2Length){
return 0;
}
else if(word1Length < word2Length){
return 1;
}
else {
return -1;
}
}
public boolean equals(MyOwnString cts){
int word1Length = ((MyOwnString)this).data.length;
int word2Length = cts.data.length;
if (word1Length != word2Length){
return false;
}
else { // if they are equal
int comparison = this.compareTo(cts);
if (comparison==0){
return true;
}
else {
return false;
}
}
}
You can't compare char[] objects with the > operator, since it's not defined on them. You'll have to iterate over the char[] arrays and compare the characters yourself.
BTW, it's very easy to cheat in this assignment, since the code of the String class is available online.
Basically what I want to do is to check on each element in an array of int, if all elements are of the same value.
I create int array as below to pass to the method for comparing each array element, it return boolean true even tough the elements are not all the same values.
Int[] denominator = {3,3,4,3};
boolean compare;
compare = bruteforce(denominator);
public static boolean bruteforce(int[] input) {
int compare =0;
int count =0;
for (int i = 0; i < input.length; i++) {
compare = input[i];
while(count<input.length){
if(input[i+1]==compare){
return true;
}
i++;
count++;
}//end while
}//end for
return false;
}//end method
I suppose the method above will loop for and keep compare for each element of the array.
When I print out the output, it showed that it only loop once, the return the boolean as true.
I really lost the clue what could be wrong in my code.
Perhaps I just overlook of some silly mistakes.
Try,
Integer[] array = {12,12,12,12};
Set<Integer> set = new HashSet<Integer>(Arrays.asList(array));
System.out.println(set.size()==1?"Contents of Array are Same":"Contents of Array are NOT same");
Explanation:
Add the array to a set and check the size os set , if it is 1 the contents are same else not.
You only need one loop and should return false as quickly as possible where applicable (i.e. when you encounter an element that doesn't match the first).
You also need to account for the edge cases that the input array is null or has one element.
Try something like this, which I minimally adapted from the code you provided...
public class BruteForceTest {
public static boolean bruteforce(int[] input) {
// NOTE: Cover the edge cases that the input array is null or has one element.
if (input == null || input.length == 1)
return true; // NOTE: Returning true for null is debatable, but I leave that to you.
int compare = input[0]; // NOTE: Compare to the first element of the input array.
// NOTE: Check from the second element through the end of the input array.
for (int i = 1; i < input.length; i++) {
if (input[i] != compare)
return false;
}
return true;
}
public static void main(String[] args) {
int[] denominator = {3,3,4,3};
boolean compare = bruteforce(denominator);
// FORNOW: console output to see where the first check landed
System.out.print("{3,3,4,3}:\t");
if (compare)
System.out.println("Yup!");
else
System.out.println("Nope!");
// NOTE: a second array to check - that we expect to return true
int[] denominator2 = {2,2};
boolean compare2 = bruteforce(denominator2);
System.out.print("{2,2}:\t\t");
if (compare2)
System.out.println("Yup!");
else
System.out.println("Nope!");
/*
* NOTE: edge cases to account for as noted below
*/
// array with one element
int[] denominator3 = {2};
System.out.print("{2}:\t\t");
if (bruteforce(denominator3))
System.out.println("Yup!");
else
System.out.println("Nope!");
// null array
System.out.print("null:\t\t");
if (bruteforce(null))
System.out.println("Yup!");
else
System.out.println("Nope!");
}
}
...and outputs:
{3,3,4,3}: Nope!
{2,2}: Yup!
{2}: Yup!
null: Yup!
If an array elements are equal you only need to compare the first element with the rest so a better solution to your problem is the following:
public static boolean bruteforce(int[] input) {
for(int i = 1; i < input.length; i++) {
if(input[0] != input[i]) return false;
}
return true;
}
You don't need more than one loop for this trivial algorithm. hope this helps.
If all elements are the same value, why not use only one for loop to test the next value in the array? If it is not, return false.
If you want to check if all elements are of same value then you can do it in a simpler way,
int arr = {3,4,5,6};
int value = arr[0];
flag notEqual = false;
for(int i=1;i < arr.length; i++){
if(!arr[i] == value){
notEqual = true;
break;
}
}
if(notEqual){
System.out.println("All values not same");
}else{
System.out.println("All values same);
}
Right now, you are not checking if "all the elements are of the same value". You are ending the function and returning true whenever (the first time) two elements are equal to each other.
Why not set the boolean value to true and return false whenever you have two elements that are not equal to each other? That way you can keep most of what you have already.
if(input[i+1]!=compare) return false;
public class Answer {
public static void main(String[] args)
{
boolean compare = false;
int count = 0;
int[] denominator = { 3, 3, 4, 3 };
for (int i = 0; i < denominator.length; i++)
{
if(denominator[0] != denominator[i])
{
count++;
}
}
if(count > 0)
{
compare = false;
} else
{
compare = true;
}
System.out.println(compare);
}
}
One mistake that I noticed right of the bat was that you declared your array as Int[], which is not a java keyword it is in fact int[]. This code checks your array and returns false if the array possesses values that are not equal to each other. If the array possesses values that are equal to each other the program returns true.
If you're interested in testing array equality (as opposed to writing out this test yourself), then you can use Arrays.equals(theArray, theOtherArray).
I want a command such as this:
setstat <statname> <level>
However, my 'statname's are in a Array; and I need to output the Array number.
This is the code I am using:
String[] statname = {"att", "def", "str", "hp",
"ranged", "pray", "magic", "cooking",
"wc", "fletch", "fish", "fm",
"craft", "smith", "mining", "herb",
"agil", "thieving", "slayer", "farming", "rc"};
int statid = statname.contains(arg[1]);
However, it doesn't work (for me). Seeing as contains(...) isn't compatible with an String[] array.
I have no idea which method to use, or how to handle this.
Use Arrays.asList(statname).indexOf(arg[1]); to find the index of an item.
Since your array is not ordered, this function will work:
public int getFoundIndex(String[] stringArr_toSearch, String str_toFind)
for(int i = 0; i < stringArr_toSearch.length; i++) {
if(stringArr_toSearch[i].equals(str_toFind)) {
return i;
}
}
return -1;
}
Call it with
int foundIdx = getFoundIndex(statName, "str");
Here's a neat code for the linear search which returns the index of the element in the array if the element is found, else returns false.
public int search(String[] array, String element)
{
if(array == null || element == null)
return -1;
for(int i = 0; i < array.length; i++)
{
if(array[i].equals(element))
return i;
}
return -1;
}
Using the approach: Arrays.asList(statname).indexOf(arg[1); can get expensive, if you have to search for the elements a lot of time.
You can sort your array once, and then do a binary search too, in order to achieve faster lookup times, if you have to search for elements in the statname array multiple times.
Below I am trying to create a method which searches through an array for a certain string and returns the position of it, if not there then -1 should be the number returned. Below I search for a word using the method and it returns -1 even though the word is within the array. Why is this?
String answer = "";
System.out.println("Enter word to search within array");
answer = in.next();
public static int search(String[] theWords, String answer) {
int a = -1;
for(int i = 0; i < theWords.length; i++) {
if (answer.equals(theWords[i])){
a = i;
break;
}
}
return a;
}
I can't see anything wrong with the code, but I would recommend eliminating the local variable that holds the return value:
public static int Search(String[] thewords, String answer) {
for (int i = 0; i < thewords.length; i++) {
if (answer.equals(thewords[i])){
return i;
}
}
return -1;
}
With this simplified logic, there's little or no chance of there being a bug in this code.
I assume this is course work, and you are not allowed to use library methods. If you were allowed, your method could be a single line:
return Arrays.asList(theWords).indexOf(answer);
You can optionally make a copy of the array since sorting might be unwanted for consumers of the method
public static int Search(String[] thewords, String answer) {
if(thewords == null) {
throw new NullPointerException();
}
String[] copy = new String[thewords.length];
System.arraycopy(thewords,0,copy,0,copy.length);
Arrays.sort(thewords);
return Arrays.binarySearch(thewords, answer);
}
Note: It returns -pos and not -1
If you need -1:
public static int Search(String[] thewords, String answer) {
if(thewords == null) {
throw new NullPointerException();
}
String[] copy = new String[thewords.length];
System.arraycopy(thewords,0,copy,0,copy.length);
Arrays.sort(thewords);
int idx = Arrays.binarySearch(thewords, answer);
return idx < 0? -1:idx;
}
Concerning your code: I believe the problem would be related to casing or spacing:
Replace with something like: if (answer.equalsIgnoreCase(theWords[i].trim())){
For large arrays go with binary search.