How can I alter the below method to work with an ArrayList?
I was thinking something like this:
public static boolean sortArrayList(ArrayList<Integer> list) {
return false;
}
but i'm not sure how to complete it.
Here is the method that I am trying to convert from working with an Array to instead work with an ArrayList:
public static boolean sortArrayList(final int[] data) {
for(int i = 1; i < data.length; i++) {
if(data[i-1] > data[i]) {
return false;
}
}
return true;
}
public static boolean sortArrayList(final ArrayList <Integer> data) {
for (int i = 1; i < data.size(); i++) {
if (data.get(i - 1) > data.get(i)) {
return false;
}
}
return true;
}
I have a few problems with the accepted answer, as given by #Sanj: (A) it doesn't handle nulls within the list, (B) it is unnecessarily specialized to ArrayList<Integer> when it could easily be merely Iterable<Integer>, and (C) the method name is misleading.
NOTE: For (A), it's quite possible that getting an NPE is appropriate - the OP didn't say. For the demo code, I assume that nulls are ignorable. Other interpretations a also fair, e.g. null is always a "least" value (requiring different coding, LAAEFTR). Regardless, the behaviour should be JavaDoc'ed - which I didn't do in my demo #8>P
NOTE: For (B), keeping the specialized version might improve runtime performance, since the method "knows" that the backing data is in an array and the compiler might extract some runtime efficiency over the version using an Iterable but such claim seem dubious to me and, in any event, I would want to see benchmark results to support such. ALSO Even the version I demo could be further abstracted using a generic element type (vs limited to Integer). Such a method might have definition like:
public static <T extends Comparable<T>> boolean isAscendingOrder(final Iterable<T> sequence)
NOTE: For (C), I follow #Valentine's method naming advice (almost). I like the idea so much, I took it one step further to explicitly call out the directionality of the checked-for-sortedness.
Below is a demonstration class that shows good behaviour for a isAscendingOrder which address all those issues, followed by similar behaviour by #Sanj's solution (until the NPE). When I run it, I get console output:
true, true, true, true, false, true
------------------------------------
true, true, true, true, false,
Exception in thread "main" java.lang.NullPointerException
at SortCheck.sortArrayList(SortCheck.java:35)
at SortCheck.main(SortCheck.java:78)
.
import java.util.ArrayList;
public class SortCheck
{
public static boolean isAscendingOrder(final Iterable<Integer> sequence)
{
Integer prev = null;
for (final Integer scan : sequence)
{
if (prev == null)
{
prev = scan;
}
else
{
if (scan != null)
{
if (prev.compareTo(scan) > 0)
{
return false;
}
prev = scan;
}
}
}
return true;
}
public static boolean sortArrayList(final ArrayList<Integer> data)
{
for (int i = 1; i < data.size(); i++)
{
if (data.get(i - 1) > data.get(i))
{
return false;
}
}
return true;
}
private static ArrayList<Integer> createArrayList(final Integer... vals)
{
final ArrayList<Integer> rval = new ArrayList<>();
for(final Integer x : vals)
{
rval.add(x);
}
return rval;
}
public static void main(final String[] args)
{
final ArrayList<Integer> listEmpty = createArrayList();
final ArrayList<Integer> listSingleton = createArrayList(2);
final ArrayList<Integer> listAscending = createArrayList(2, 5, 8, 10 );
final ArrayList<Integer> listPlatuea = createArrayList(2, 5, 5, 10 );
final ArrayList<Integer> listMixedUp = createArrayList(2, 5, 3, 10 );
final ArrayList<Integer> listWithNull = createArrayList(2, 5, 8, null);
System.out.print(isAscendingOrder(listEmpty ) + ", ");
System.out.print(isAscendingOrder(listSingleton) + ", ");
System.out.print(isAscendingOrder(listAscending) + ", ");
System.out.print(isAscendingOrder(listPlatuea ) + ", ");
System.out.print(isAscendingOrder(listMixedUp ) + ", ");
System.out.print(isAscendingOrder(listWithNull ) + "\n");
System.out.println("------------------------------------");
System.out.print(sortArrayList(listEmpty ) + ", ");
System.out.print(sortArrayList(listSingleton) + ", ");
System.out.print(sortArrayList(listAscending) + ", ");
System.out.print(sortArrayList(listPlatuea ) + ", ");
System.out.print(sortArrayList(listMixedUp ) + ", ");
System.out.print(sortArrayList(listWithNull ) + "\n");
}
}
Try below function, it takes integer array and converts it into a ArrayList and then computes the result :
public static boolean sortArrayList(final int[] data) {
List<Integer> aList = new ArrayList<Integer>();
for (int index = 0; index < data.length; index++)
aList.add(data[index]);
for (int i = 1; i < aList.size(); i++) {
if (aList.get(i - 1) > aList.get(i)) {
return false;
}
}
return true;
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Question:
Write a Number class that can be used to determine if a number is odd, even, or
perfect. Then, use this Number class to determine how many numbers in the list are odd, even, and perfect.
Number Class:
public class Number
{
private Integer number;
public Number(int n)
{
number=n;
}
public boolean isEven()
{
if(number % 2 == 0)
return true;
else
return false;
}
public boolean isOdd()
{
if(number % 2 != 0)
return true;
else
return false;
}
public boolean isPerfect()
{
int count = 0;
for(int i = 1; i<number; i++)
{
if(number % i == 0)
count += i;
}
if(number == count)
{
return true;
}
else
return false;
}
public String toString()
{
return "" +number;
}
}
My number class is running good there is no problem in my Number class. But in my number analyzer class where i find the number of odd,even and perfect.
Number Analyzer class:
public class NumberAnalyzer
{
private ArrayList<Number> list;
public NumberAnalyzer(int l)
{
list=l;
}
public int countOdds()
{
int odd = 0;
for(int i=0; i<list.size(); i++)
{
if(list.isOdd() == true)
return odd++;
}
}
public int countEvens()
{
int even = 0;
for(int x = 0; x<list.size(); x++)
{
if(list.isEven() == true)
return even++;
}
}
public int countPerfects()
{
int perfect = 0;
for(int z = 0; z<list.size(); z++)
{
if(list.isPerfect() == true)
return perfect++;
}
}
public String toString()
{
return "" + list;
}
}
Please make correction on this class so my program run perfectly. I do not understand the problem please make change in this so program work perfectly.
Runner of program:
import static java.lang.System.*;
public class Runner
{
public static void main( String args[] )
{
int[] r = {5, 12, 9, 6, 1, 4, 8, 6 };
NumberAnalyzer test = new NumberAnalyzer(r);
out.println(test);
out.println("odd count = "+test.countOdds());
out.println("even count = "+test.countEvens());
out.println("perfect count = "+test.countPerfects()+"\n\n\n");
}
}
Correct answers with this Runner:
[5, 12, 9, 6, 1, 4, 8, 6]
odd count = 3
even count = 5
perfect count = 2
Thank you
I didn't understand how it could work if it even didn't complile but nevermind. You need to change 2 classes: NumberAnalyzer and Runner. Please have a look:
public class Runner {
public static void main(String args[]) {
Number[] r = {new Number(5), new Number(12), new Number(9), new Number(6),
new Number(1), new Number(4), new Number(8), new Number(6)};
NumberAnalyzer test = new NumberAnalyzer(r);
out.println(test);
out.println("odd count = " + test.countOdds());
out.println("even count = " + test.countEvens());
out.println("perfect count = " + test.countPerfects() + "\n\n\n");
}
}
and
import java.util.Arrays;
import java.util.List;
public class NumberAnalyzer {
private List<Number> list;
public NumberAnalyzer(Number[] l) {
list = Arrays.asList(l);
}
public int countOdds() {
int odd = 0;
for (Number value : list) {
if (value.isOdd() == true) {
odd++;
}
}
return odd;
}
public int countEvens() {
int even = 0;
for (Number value : list) {
if (value.isEven() == true) {
even++;
}
}
return even;
}
public int countPerfects() {
int perfect = 0;
for (Number value : list) {
if (value.isPerfect() == true) {
perfect++;
}
}
return perfect;
}
public String toString() {
return "" + list;
}
}
in that case it returns a correct output.
Your approach for resolving this problem has a lot of problems, especially in NumberAnalyzer class.
1) You should call the isOdd(), isEven() etc. on an element of the list, not on the list itself -> list.get(i).isEven()
2) The return even++ will exit the loop and return 1 if the condition is met, and the method is not even working since you don't have a return statement in case if the if statement from the for loop doesn't get executed.
3) Not a big problem, but the x and z can be declared as i too -> more intuitive ( i ndex)
4) The isPerfect() method is not correct, an easy solution to solve this problem could be using Math.sqrt() and Math.floor()
5) You're trying to pass an int[] array and the constructor expect an int. And after this, you have an ArrayList<Number> inside the NumberAnalyzer class and you're trying to assign to this list an int value.
Solutions:
1) + 2) + 3) :
public class NumberAnalyzer {
private List<Number> list; //Changed the ArrayList<> to List<>
public NumberAnalyzer(List<Number> l) {
list = l;
}
public int countOdds() {
int odd = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).isOdd())
odd++;
}
return odd;
} // SAME FOR THE OTHER METHODS.
}
4)
public boolean isPerfect()
{
int square = Math.sqrt(number);
return (square - Math.floor(square)) == 0;
}
5) The static void main method should now look like this:
Integer[] r = {5, 12, 9, 6, 1, 4, 8, 6};
List<Integer> rList = Arrays.asList(r);
List<Number> numberList = rList.stream().map(Number::new).collect(Collectors.toList());
NumberAnalyzer test = new NumberAnalyzer(numberList);
I have a text file containing the following strings (which are versions of a software):
1_10_2_0_154
3_10_5_2_10
2_10_4_1
3_10_5_1_37
I'm trying to find the most recent version, in this case 3_10_5_2_10 is the version that I'm trying to display using java.
For the moment, here is my code:
BufferedReader br;
String version;
ArrayList<List<Integer>> array = new ArrayList<List<Integer>>();
List<Integer> liste = new ArrayList<Integer>();
try{
br = new BufferedReader(new FileReader(new File(FILEPATH)));
while((version= br.readLine()) != null)
{
liste = Arrays.asList(version.split("_")).stream().
map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());
array.add(liste);
}
for(int i = 0; i < array.size(); i++)
{
for (List l: array)
{
Object z = l.get(i);
List<Object> listes = new ArrayList<Object>();
listes.add(z);
System.out.println(listes);
}
}
br.close();
System.out.println(array);
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
I made a loop to save strings to ArrayList> like:
[[1,10,2,0,154] , [3,10,5,2,10], [2,10,4,1], [3,10,5,1,37]]
I want to get the elements of each list and compare them to find the most biggest one (most recent one) but I don't know to do that..
I sugguest you a object approach, define a class named Version with compareTo method, then using method sort on Collections class you can simply sort your versions.
Advantages
Clean and Clear code
Data validation
Main:
public class Main {
public static void main(String[] args){
List<Version> versions = Arrays.asList(
Version.create("1_10_2_0_154"),
Version.create("3_10_5_2_10"),
Version.create("2_10_4_1_49"),
Version.create("3_10_5_1_37"));
versions.sort(Version::compareTo);
System.out.println(versions.get(0).toString());
}
}
Version:
public class Version implements Comparable<Version> {
private final int major;
private final int minor;
private final int bug;
private final int release;
private final int build;
public Version(int major, int minor, int bug, int release, int build) {
this.major = major;
this.minor = minor;
this.bug = bug;
this.release = release;
this.build = build;
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getBug() {
return bug;
}
public int getRelease() {
return release;
}
public int getBuild() {
return build;
}
#Override
public String toString() {
return "Version{" +
"major=" + major +
", minor=" + minor +
", bug=" + bug +
", release=" + release +
", build=" + build +
'}';
}
public static Version create(String value){
String[] splitRes = value.split("_");
List<Integer> intValues = new ArrayList<>();
for(String v : splitRes){
intValues.add(Integer.parseInt(v));
}
return create(intValues);
}
public static Version create(List<Integer> values){
if(Objects.requireNonNull(values).size() < 5)
throw new IllegalArgumentException();
return new Version(
values.get(0),
values.get(1),
values.get(2),
values.get(3),
values.get(4)
);
}
#Override
public int compareTo(Version that) {
if (this.major > that.major) {
return -1;
} else if (this.major < that.major) {
return 1;
}
if (this.minor > that.minor) {
return -1;
} else if (this.minor < that.minor) {
return 1;
}
if (this.bug > that.bug) {
return -1;
} else if (this.bug < that.bug) {
return 1;
}
if (this.release > that.release) {
return -1;
} else if (this.release < that.release) {
return 1;
}
if (this.build > that.build) {
return -1;
} else if (this.build < that.build) {
return 1;
}
return 0;
}
}
UPDATE 1
As suggested by #Henrik i updated the list sorting with a Java 8 approach.
UPDATE 2
I reversed the compareTo method so now you can simply do plain sort calling sort method on list and passing method reference Version::compareTo
UPDATE 3
A more dynamic solution for Version class:
public class Version implements Comparable<Version> {
private final List<Integer> values;
public Version(List<Integer> values) {
this.values = values;
}
public List<Integer> getValues() {
return values;
}
#Override
public String toString() {
return String.join("_", values
.stream()
.map(Object::toString)
.collect(Collectors.toList()));
}
#Override
public int compareTo(Version that) {
List<Integer> thatValues = that.getValues();
for(int index = 0; index < values.size(); index++){
Integer value = values.get(index);
Integer thatValue = thatValues.get(index);
if (value > thatValue) {
return -1;
} else if (value < thatValue) {
return 1;
}
}
return 0;
}
public static Version create(String value){
String[] splitRes = value.split("_");
List<Integer> intValues = new ArrayList<>();
for(String v : splitRes){
intValues.add(Integer.parseInt(v));
}
return new Version(intValues);
}
}
You can write a Comparator to compare two Lists
Comparator<List<Integer>> comparator = (list1, list2) -> {
Iterator<Integer> iteratorA = list1.iterator();
Iterator<Integer> iteratorB = list2.iterator();
//It iterates through each list looking for an int that is not equal to determine which one precedes the other
while (iteratorA.hasNext() && iteratorB.hasNext()) {
int elementA = iteratorA.next();
int elementB = iteratorB.next();
if (elementA > elementB) {
return 1;
} else if (elementA < elementB) {
return -1;
}
}
//All elements seen so far are equal. Use the list size to decide
return iteratorA.hasNext() ? 1 : iteratorB.hasNext() ? -1 : 0;
};
You can sort it as
Collections.sort(list, comparator);
EDIT: You can refer to David Geirola's answer to convert the version string as a POJO and move the comparator logic inside that. But that is highly tied/coupled to the input string format. My solution works for any List<List<Integer>>.
A simple object oriented approach would be to create object, representing version number, let's call it VersionNumber, which would have a constructor of a factory method that does the parsing of the string. This VersionNumber class should implement interface Comparable and implement method compareTo.
Here is a hint for using Comparable Why should a Java class implement comparable?
Then you can easily write an algorithm to find the max version or google some library that would do it for you.
It is not optimized but should work. You can use both of comparators.
static List<String> versions = Arrays.asList(
"1_10_2_0_154",
"3_10_5_2_10",
"2_10_4_1_49",
"3_10_5_1_37");
static Comparator<List<Integer>> c = (o1,o2) -> {
int length = o1.size()>o2.size()?o2.size():o1.size();
for (int i = 0; i < length; i++) {
int i1 = o1.get(i);
int i2 = o2.get(i);
if (i1 != i2)
return i1 - i2;
}
return 0;
};
static Comparator<List<Integer>> c2 = (o1,o2) -> {
Iterator<Integer> i1=o1.iterator();
Iterator<Integer> i2=o2.iterator();
while (i1.hasNext() && i2.hasNext()){
int i = i1.next()-i2.next();
if (i!=0) return i;
}
return 0;
};
static Optional<List<Integer>> getTheMostRecentVersion(List<String> versions) {
return versions.stream().
map(s -> Arrays.stream(s.split("_")).
map(Integer::parseInt).
collect(Collectors.toList())).max(c2);
}
I think that this text file could be very big and it is better to compare each line on the fly (instead of store all line into collection to sort it after):
public static String getMostRecentVersion(BufferedReader in) throws IOException {
final Comparator<String[]> version = (s1, s2) -> {
int res = 0;
for (int i = 0; i < 5 && res == 0; i++)
res = Integer.compare(Integer.parseInt(s1[i]), Integer.parseInt(s2[i]));
return res;
};
String str;
String resStr = null;
String[] resPparts = null;
while ((str = in.readLine()) != null) {
String[] parts = str.split("_");
if (resStr == null || version.compare(parts, resPparts) > 0) {
resStr = str;
resPparts = parts;
}
}
return resStr;
}
A general ListComparator should help.
static class ListComparator<T extends Comparable<T>> implements Comparator<List<T>> {
#Override
public int compare(List<T> o1, List<T> o2) {
for (int i = 0; i < Math.max(o1.size(), o2.size()); i++) {
int diff =
// Off the end of both - same.
i >= o1.size() && i >= o2.size() ? 0
// Off the end of 1 - the other is greater.
: i >= o1.size() ? -1
: i >= o2.size() ? 1
// Normal diff.
: o1.get(i).compareTo(o2.get(i));
if (diff != 0) {
return diff;
}
}
return 0;
}
}
private static final Comparator<List<Integer>> BY_VERSION = new ListComparator<Integer>().reversed();
public void test(String[] args) {
String[] tests = {
"1_10_2_0_154",
"3_10_5_2_10",
"2_10_4_1_49",
"3_10_5_1_37",
"3_10_5_1_37_0"
};
System.out.println("Before: " + Arrays.toString(tests));
System.out.println("After: " + Arrays.stream(tests)
// Split into parts.
.map(s -> s.split("_"))
// Map String[] to List<Integer>
.map(a -> Arrays.stream(a).map(s -> Integer.valueOf(s)).collect(Collectors.toList()))
// Sort it.
.sorted(BY_VERSION)
// Back to a new list.
.collect(Collectors.toList()));
}
slap your arrays together into a number then just do number comparison.
class Scratch
{
public static void main(String[] args)
{
List<List<Integer>> arr = new ArrayList<>();
arr.add(fromArray(new Integer[]{1,10,2,0,154}));
arr.add(fromArray(new Integer[]{3,10,5,2,10}));
arr.add(fromArray(new Integer[]{2,10,4,1,49}));
arr.add(fromArray(new Integer[]{3,10,5,1,37}));
Integer[] maxLengths = {0,0,0,0,0};
for (List<Integer> v : arr)
{
for(int idx = 0; idx < v.size(); idx++)
{
Integer n = v.get(idx);
int curMaxLen = maxLengths[idx];
maxLengths[idx] = Math.max(n.toString().length(), curMaxLen);
}
}
Long largest = arr.stream().map(v -> {
StringBuilder result = new StringBuilder();
for(int idx = 0; idx < v.size(); idx++)
{
Integer n = v.get(idx);
int maxLen = maxLengths[idx];
result.append(String.format("%-" + maxLen + 's', n).replace(' ', '0'));
}
return result.toString();
}).map(Long::valueOf).max(Comparator.naturalOrder()).get();
System.out.println(largest);
}
public static List<Integer> fromArray(Integer[] array)
{
List<Integer> list = new ArrayList<>();
Collections.addAll(list, array);
return list;
}
}
public class ArrayMethodsTest
{
public static void main(String[] args)
{
int[] tester = {0,1,2,3,4,5};
ArrayMethods test = new ArrayMethods(tester);
for(int element : test)
{
System.out.print(element + " ");
}
test.shiftRight();
for(int element : test) //error: for-each not applicable to expression type
{
System.out.print(element + " ");
}
}
}
I figure what the problem is. Thanks to jigar joshi. However I still need to use the ArrayMethods methods for the tester that I created. I know that they work but how can it be possible to provide a tester class for an object that isn't an array since the methods are for arrays.
public class ArrayMethods
{
public int[] values;
public ArrayMethods(int[] initialValues)
{
values = initialValues;
}
public void swapFirstAndLast()
{
int first = values[0];
values[0] = values[values.length-1];
values[values.length-1] = first;
}
public void shiftRight()
{
int first = 0;
int second = first;
for(int i =0; i < values.length; i++)
{
if(i < values.length-1)
{
first = values[i];
second = values[i+1];
values[i+ 1] = first;
}
if(i == values.length)
{
values[i] = values[0];
}
}
}
}
//0,1,2,3,4,5
//5,0,1,2,3,4
test is reference of ArrayMethods which is not an Iterable or an array type and so is the error
You've already encountered the issue in which you can't iterate over an ArrayMethods, since it's not iterable. What it seems like you want to do is iterate over its values instead, considering that values is a public field.
for(int element : test.values) {
System.out.print(element + " ");
}
I have written a program which takes the words the user have entered, with a button press, and puts them in an ArrayList. There is also another text field where the user can enter a letter or word, for which the user can search for in the ArrayList with another button press. I'm using a sequential search algorithm to accomplish this, but it does not work as I expect it to; If the searched word is found, the search function should return, and print out in a textArea that the word was found and where in the array it was found. This works, but only for the first search. If the word is not found, the function should print out that the word was not found. This works as I want it to.
The problem is that after I searched for one word, and it displays where in the ArrayList this can be found, nothing happens when I press the button after that, whether the entered letter/word is in the array or not. It's like the string that the text gets stored isn't changing. I don't understand why... Here below is the custom Class of the search function and then my Main class:
public class Search {
static private int i;
static String index;
static boolean found = false;
public static String sequencial (ArrayList<String> list, String user) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals(user)) {
index = "The word " + user + " exist on the place " + i + " in the Arraylist";
found = true;
}
}
if (!found) {
index = "The word " + user + " could not be found";
}
return index;
}
My Main class:
ArrayList<String> list = new ArrayList<String>();
ArrayList<String> s = new ArrayList<String>();
private void btnAddActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
txtaOutput.setText("");
String word = txtfAdd.getText();
list.add(word);
for (int i = 0; i < list.size(); i++) {
txtaOutput.append("" + list.get(i) + "\n");
}
}
private void btnSearchActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String user = txtfSearch.getText();
txtaOutput.setText("");
String index = Search.sequencial(list, user);
txtaOutput.setText("" + index);
}
Any help is appreciated!
The problem is that you declared your found variable as static. When your first word is found, it is set to true, and nothing ever sets it back to false. Instead of making it a static variable, declare it as a local variable inside your sequencial (it's spelled sequential, by the way) function, just before the for-loop.
In fact, all the variables you've declared as static should be made local. Declaring static variables is never a good idea.
As said by other users:
There is the List#indexOf(Object) method. You should use that instead of reinventing the wheel (unless you need to, and in that case you might have a look at the ArrayList implementation). There are also other collections, like HashSet which are more apropiate for looking up, but i guess that is another history.
The scope and the names of the variables (i, index, found) is error-prone. Do other methods or even classes need to have access to those variables? If you need to keep those variables, you might want to choose a visibility (public,protected,private). "index" is a misleading choice of a name for a message.
This would be an slightly simplified/corrected version of your code:
// Ommit those unneeded static variables
public static String sequencial (ArrayList<String> list, String user) {
int indexFound = list.indexOf(user);
if (user >= 0) {
return "The word " + user + " exist on the place " + indexFound + " in the Arraylist";
} else {
return "The word " + user + " could not be found";
}
}
...
private void btnSearchActionPerformed(java.awt.event.ActionEvent evt) {
String user = txtfSearch.getText();
// txtaOutput.setText("");
String seqMessage = sequencial(list, user);
txtaOutput.setText(seqMessage);
}
We use the static properties when you would like to use the constants. You should not use the static properties here. The problem will happen when your found property is changed the first time, it will not be changed again. And from that time, it will always be true. Similar with index property. Here is the code you can fix this:
public class Search {
public static SearchResult sequencial (ArrayList<String> list, String user) {
SearchResult result = null;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals(user)) {
String index = "The word " + user + " exist on the place " + i + " in the Arraylist";
boolean found = true;
result = new SearchResult(index, found);
break;
}
}
if (result == null) {
String index = "The word " + user + " could not be found";
result = new SearchResult(index);
}
return result;
}
//sample inner class
static class SearchResult {
private String index;
private boolean found;
public SearchResult(String index) {
this.index = index;
}
public SearchResult(String index, boolean found) {
this.index = index;
this.found = found;
}
public String getIndex() {
return index;
}
public void setIndex(String index) {
this.index = index;
}
public boolean isFound() {
return found;
}
public void setFound(boolean found) {
this.found = found;
}
}
}
public class SequencialSearcher {
public static int SequencialSearchInt(int[] inputArray, int key)
{
for(int i=0; i < inputArray.length ; i++)
{
if(inputArray[i] == key)
{
return i;
}
}
return -1;
}
public static int SequencialSearchString(String[] array, String key)
{
for(int i=0; i < array.length ; i++)
{
if(array[i] == key)
{
return i;
}
}
return -1;
}
public static int SequencialSearchFloat(double[] array, double key)
{
for(int i=0; i < array.length ; i++)
{
if(array[i] == key)
{
return i;
}
}
return -1;
}
public static void main (String args[])
{
//select the type of the elements of search
//1 if integers
//2 if float
//3 if string
int x = 3;
int[] array1 = {9, 0, 10, 8, 5, 4, 6, 2, 3};
double[] array2 = {9.0, 0.0, 10.0, 8.0, 5.0, 4.0, 6.0, 2.0, 3.0};
String[] array3 = {"aa","hey", "hello"};
if(x == 1){
//enter the integer you want to search for here below
int requiredValue = 5;
int result = SequencialSearchInt(array1, requiredValue);
if (result != -1)
{
System.out.println("Required Value: "+requiredValue+" found at index: "+result);
}
else
{
System.out.println("Value:"+requiredValue+" not found");
}
}
else if(x == 2)
{
//enter the double you want to search for here below
double requiredValue1 = 5.0;
int result = SequencialSearchFloat(array2, requiredValue1);
if (result != -1)
{
System.out.println("Required Value: "+requiredValue1+" found at index: "+result);
}
else
{
System.out.println("Value:"+requiredValue1+" not found");
}
}
else if(x == 3){
//enter the string you want to search for here below
String requiredValue2 = "hey";
int result = SequencialSearchString(array3, requiredValue2);
if (result != -1)
{
System.out.println("Required Value: "+requiredValue2+" found at index: "+result);
}
else
{
System.out.println("Value:"+requiredValue2+" not found");
}
}
else{
System.out.println("Error. Please select 1,2 and 3 only");
}
}
}
This method should return the index of the first string that starts with the target.
Return -1 if no string starts with the target.
My implementations works but not covers all variations.
Code:
public int getIndex(ArrayList<String> text, String target)
{
int i = 0;
int index = -1;
boolean found = false;
while (!found && i < text.size()) //supply condition
{
for (String s : text) {
if (s.contains(target)) {
found = true;
} else {
i++;
}
if (found) index = i;
}
}
return index;
}
testing part:
public static void main(String[] args)
{
ArrayList<String> cities = new ArrayList<String>();
cities.add("Chicago");
cities.add("Houston");
cities.add("San Jose");
cities.add("Seattle");
cities.add("Denver");
Finder finder = new Finder();
System.out.println(finder.getIndex(cities, "C"));
System.out.println("Expected: 0");
System.out.println(finder.getIndex(cities, "S"));
System.out.println("Expected: 2");
System.out.println(finder.getIndex(cities, "D"));
System.out.println("Expected: 4");
System.out.println(finder.getIndex(cities, "X"));
System.out.println("Expected: -1");
}
This code has coverage 50/50 input:
4
- Expected: 0
3
- Expected: 2
4
+ Expected: 4
-1
+ Expected: -1
How to solve this issue?
You claim:
My implementations works
It doesn't look like it to me, based on the tests. Your code is much more complicated than it needs to be, which is making it hard to find the bug. The problem is that you've got two loops for no reason:
while (!found && i < text.size()) //supply condition
{
for (String s : text) {
}
}
Why have you got both of those loops? You're incrementing i multiple times within the inner loop...
You'd probably find it easier to get all the tests to pass if you simplify it:
public int getIndex(List<String> text, String target) {
for (int i = 0; i < text.size(); i++) {
if (text.get(i).startsWith(target)) {
return i;
}
}
return -1;
}
This is one of those cases where a dogmatic insistence on only having one return statement per method leads to much messier code.
Note that I've changed the condition from contains (in your code) to startsWith to match the description. You should add a test for this difference - try to find a string which is present in one of the cities, but the city doesn't start with that value.
I've also changed the parameter type to List<String> as you don't really need it to be an ArrayList<String>. (With a bit of work you could make it accept Iterable<String> instead, but that would be more complicated.)
I'd also recommend that you start using JUnit or something similar for your testing, rather than just using System.out.println.
EDIT: Just for a bit of fun, a version which takes Iterable<String> and uses that to handle even LinkedList<String> efficiently:
public int getIndex(Iterable<String> elements, String target) {
int index = 0;
for (String element : elements) {
if (element.startsWith(target)) {
return index;
}
index++;
}
return -1;
}
(Not that much harder after all...)
public int getIndex(ArrayList<String> text, String target)
{
for(int i=0;i < text.size();i++)
{
if(text.get(i).indexOf(target) == 0)
return i;
}
return -1;
}
Making the following changes:
Get rid of unnecessary found variable
Replace contains with startsWith
Remove the for-loop, otherwise you pass through the data a few times
Change the while-loop to a for-loop
I get to this, which seems to work:
public int getIndex(ArrayList<String> text, String target)
{
int index = -1;
for (int i = 0; index == -1 && i < text.size(); i++)
{
if (text.get(i).startsWith(target))
{
index = i;
}
}
return index;
}
You can of course improve on it a lot more still.
Change the getIndex method with this:
public int getIndex(ArrayList<String> text, String target)
{
int i = 0;
for (String s : text) {
// Use startsWith if you want to check if the string starts with target...
// Use contains if you want to check if contains target...
if (s.startsWith(target)) {
return i;
}
i++;
}
return -1;
}