Java ArrayList not working on characters in my case - java

I have a big doubt. I want to find the first char of a string here which isn't repeated.For e.g. for the input below should return 'c'. So this is how I was planning on doing it. But I noticed the remove method is looking to remove at an index of 98 vs removing the object "a". How do I force it to remove the object "a" instead of removing from index ?
Why doesn't this work ?
And what can I do to change this ?
Is ArrayList always guaranteed to store things in order ?
public void findStartingLetter()
{
String[] array={"a","b","c","d","b","a","d","d","d"};
List<Character> list = new ArrayList<Character>();
for(String i:array)
{
if(list.contains(i.charAt(0)))
list.remove(i.charAt(0));
else
list.add(i.charAt(0));
}
}
EDIT:
Performance wise is this an O(n) function ?

You have to cast manually to a Character since the char gets casted to an int, which in turn goes by index and not value.
list.remove((Character) i.charAt(0));
Will ensure that it is done properly.

Is ArrayList always guaranteed to store things in order ?
Depends on your definition of order:
If you mean the order you add them, Yes.
If you mean numerical/alphabetical order, then No, but you can sort it by using
Collections.sort(list)
This will sort by the natural ascending order of the objects in the list.

I'm not entirely sure why you want to use a List for this, but I would instead recommend a Set - it's guaranteed to not contain duplicates.
Here's the first approach, with a set:
public Set<Character> addToSet(String[] elements) {
Set<Character> res = new HashSet<>();
for(String c : elements) {
res.add(c.charAt(0));
}
return res;
}
Now, if you really want to do this with a List, then it's similar code - you just need to check to see if the element exists before you add it in.
public List<Character> addUnique(String[] elements) {
List<Character> res = new ArrayList<>();
for(String item : elements) {
Character c = item.charAt(0);
if(!res.contains(c)) {
res.add(c);
}
}
return res;
}

Your approach to this problem is quite confusing and you ask many questions which do not seem to relate to your problem.
Why not just use:
String testString = "abcdbaddd";
Character retVal = null;
for (int i = 0; i < testString.length() -1; i++) {
if (testString.charAt(i) == testString.charAt(i + 1)) {
retVal = testString.charAt(i);
break;
}
}
return retVal;
That gets you the first non-repeated character (I'm assuming that by repeated you mean repeated and adjacent) or null if no such character exists.

Related

How can I tell if the elements in an Array List are same or different?

I'm trying to verify if all the elements in an array list are same or not. This is my code:
ArrayList<Integer> arr = new ArrayList<>(Arrays.asList(2,2,4,2));
for (int z = 0; z < arr.size(); z++) {
if(!arr.get(z++).equals(arr.get(z--))) {
System.out.println("same");
}else {
System.out.println("differnt");
}
}
Put the elements into a Set. If the resulting set has a size of 1, then all elements have been the same. One line of code, no loops, no indices, works with every collection:
boolean allTheSame = new HashSet<Integer>(list).size() == 1;
System.out.println(allTheSame ? "same" : "different");
(Edited:)
It might be worth noting that if the list is large, and likely contains many different elements, then constructing a Set will impose some memory overhead that can be avoided, if desired. In this case, you'd iterate over the list and compare all elements to the first one. But you should not check the elements for identity with ==. Instead, you should compare them using their equals method, or, if you graciously want to handle null entries, using Objects#equals.
An example of how to solve this efficiently and generically is given in the answer by Zabuza
There are various solutions to this.
Compare any with others
You just need to pick any element (the first, for example) and then compare this to all other elements. A single simple loop is enough:
public static <E> areElementsEquals(List<E> list) {
// Edge cases
if (list == null || list.size() <= 1) {
return true;
}
// Pick any element
E any = list.get(0);
// Compare against others
for (E other : list) {
// Use Objects#equals for null-safety
if (!Objects.equals(any, other)) {
return false;
}
}
return true;
}
Or a Stream-API version:
return list.stream()
.allMatch(other -> Objects.equals(any, other));
If you checked that any is not null, you could also use a method reference:
return list.stream()
.allMatch(any::equals);
Set
Sets do not have duplicates. You can put all your elements into a Set and check if the size is 1, then all other elements were duplicates.
return new HashSet<>(list).size() == 1;
While this code is pretty compact, I would favor the more straightforward solution of iterating. It is a bit more readable and also more efficient, since it does not have the additional overhead of setting up a set.
You only have to compare the 1st item against all the others:
int a = arr.get(0);
boolean allSame = true;
for (int z = 1; z < arr.size(); z++) {
allSame = (a == arr.get(z));
if (!allSame) break;
}
if (allSame)
System.out.println("Same");
else
System.out.println("Different");
. . . and does your code work? What sort of output do you get? Are you suffering any exceptions?
Don't declare your List as ArrayList; declare it as List. Don't call a List arr; it isn't an array. Call it numbers or something like that.
Why have you got the bang sign/not operator in line 3? I think that shouldn't be there.
If you think about the different kinds of collection/data structure available, which you can read about here, you will find a collection type whose size() method will tell you how many distinct elements you have.
You just have to compare the current element with the next, if they are different that means you don't have all elements the same:
for(int i = 0; i < list.size() - 1; i++) {
if (list.get(i) != list.get(i + 1)) {
return false; // elements are different
}
}
return true; // all element are the same
Try this :
String first = arr.get(0);
boolean allTheSame = true;
if (arr.size() > 1) {
for (int z = 1; z < arr.size(); z++) {
if (!arr.get(z).equals(first)) {
allTheSame = false;
break;
}
}
}
A method use BitSet to judge are all elements in list is same or not,it need less memory and run faster.
public static boolean areAllElementsSame(List<Integer> numbers) {
BitSet set = new BitSet();
numbers.forEach(new Consumer<Integer>() {
#Override
public void accept(Integer integer) {
set.set(integer);
}
});
return set.cardinality() == 1;
}
This method can also used to figure out how many different elements.
same is a flag that stores the result we intend.
uv is the uniformality variable.
Object is the type of object you stored in list (the arraylist)
import java.util.*;
class Main{
public static void main(String args[]){
ArrayList<Integer> arr = new ArrayList<>(Arrays.asList(2,2,2,2));
boolean same=true;
Object uv=arr.get(0);
for (Object i: arr){
if(!i.equals(uv)){
same=false;
break;
}
}
System.out.print("Result:"+same);
}
}
You will have to check for each element, if all the elements on later indexes are same as that one or different than it.
You can do it using a nested loop like this:
public static void main(String[] args) {
// write your code here
ArrayList<Integer> arr = new ArrayList<Integer>(Arrays.asList(2,2,4,2));
boolean result=true;
for (int i = 0; i < arr.size(); i++) {
for (int j=i; j<arr.size(); j++){
if (!arr.get(i).equals(arr.get(j))){
result=false;
}
}
}
System.out.println(result);
}
the 2nd loop starts from j=i and goes till the right end of the array because you don't need to check the left side of that index as it is already checked in the previous iterations and the result would already have been updated to false.
If you want to ensure that the list contains at least two different elements, you have to "walk" the array once: you compare the first element against all others, and stop on the first mismatch. On mismatch: not all elements are the same, otherwise they are all the same!
But the initial question was a bit unclear. If you want to determine if there are no two equal elements in the array, you have to compare all entries against all others! Then you need two loops: you pick all elemenst in order, to compare them to all others (respectively to all following ones: you already compared slot 1 to all other slots, so you would only have to compare slot 2 to slot3 ... til end).
Another approach would be to use a Set implementation, for example HashSet! Sets have unique members. So when you turn your list into a set, and the set has less entries than the list, you know that the list contains duplicates.

How to check multiple contains operations faster?

I have a String list as below. I want to do some calculations based on if this list has multiple elements with same value.
I got nearly 120k elements and when I run this code it runs too slow. Is there any faster approach than contains method?
List<String> words= getWordsFromDB(); //words list has nearly 120k elements
List<String> tempWordsList = new LinkedList<String>(); //empty list
String[] keys = getKeysFromDB();
List<String> tempKeysList = new LinkedList<String>();
for (int x = 0; x < words.size(); x++) {
if (!tempWordsList.contains(words.get(x))) {
tempWordsList.add(words.get(x));
String key= keys[x];
tempKeysList.add(key);
} else {
int index = tempWordsList.indexOf(words.get(x));
String m = tempKeysList.get(index);
String n = keys[x];
if (!m.contains(n)) {
String newWord = m + ", " + n;
tempKeysList.set(index, newWord);
}
}
}
EDIT: words list comes from database and problem is there is a service continuously updating and inserting data to this table. I don't have any access to this service and there are other applications who is using the same table.
EDIT2: I have updated for full code.
You are searching the list twice per word: once for contains() and once for indexOf(). You could replace contains() by indexOf(), test the result for -1, otherwise reuse the result instead of calling indexOf() again. But you are certainly using the wrong data structure. What exactly do you need a for? Do you need a? I would use a HashSet, or a HashMap if you need to associate other data with each word.
//1) if you can avoid using linked list use below solution
List<String> words= getWordsFromDB(); //words list has nearly 120k elements
//if you can avoid using linked list, use set instead
Set<String> set=new HashSet<>();
for (String s:words) {
if (!set.add(s)) {
//do some calculations
}
}
//2) if you can't avoid using linked list use below code
List<String> words= getWordsFromDB(); //words list has nearly 120k elements
List<String> tempList = new LinkedList<String>(); //empty list
//if you can't avoid LinkedListv (tempList) you need to use a set
Set<String> set=new HashSet<>();
for (String s:words) {
if (set.add(s)) {
tempList.add(s);
} else {
int a = tempList.indexOf(s);
//do some calculations
}
}
LinkedList.get() runs in O(N) time. Either use ArrayList with O(1) lookup time, or avoid indexed lookups altogether by using an iterator:
for (String word : words) {
if (!tempList.contains(word)) {
tempList.add(word);
} else {
int firstIndex = tempList.indexOf(word);
//do some calculations
}
}
Disclaimer: The above was written under the questionable assumption that words is a LinkedList. I would still recommend the enhanced-for loop, since it's more conventional and its time complexity is not implementation-dependent. Either way, the suggestion below still stands.
You can further improve by replacing tempList with a HashMap. This will avoid the O(N) cost of contains() and indexOf():
Map<String, Integer> indexes = new HashMap<>();
int index = 0;
for (String word : words) {
Integer firstIndex = indexes.putIfAbsent(word, index++);
if (firstIndex != null) {
//do some calculations
}
}
Based on your latest update, it looks like you're trying to group "keys" by their corresponding "word". If so, you might give streams a spin:
List<String> words = getWordsFromDB();
String[] keys = getKeysFromDB();
Collection<String> groupedKeys = IntStream.range(0, words.size())
.boxed()
.collect(Collectors.groupingBy(
words::get,
LinkedHashMap::new, // if word order is significant
Collectors.mapping(
i -> keys[i],
Collectors.joining(", "))))
.values();
However, as mentioned in the comments, it would probably be best to move this logic into your database query.
Acutally, tempList use linear complexity time methods :
if (!tempList.contains(words.get(x))) {
and
int a = tempList.indexOf(words.get(x));
It means that at each invocation of them, the list is in average iterate at half.
Besides, these are redundant.
indexOf() only could be invoked :
for (int x = 0; x < words.size(); x++) {
int indexWord = tempList.indexOf(words.get(x));
if (indexWord != -1) {
tempList.add(words.get(x));
} else {
//do some calculations by using indexWord
}
}
But to improve all accesses, you should change your structure : wrapping or replacing LinkedList by LinkedHashSet.
LinkedHashSet would keep the actual behavior because as List, it defines the iteration ordering, which is the order in which elements were inserted into the set but it also uses hashing feature to improve time access to its elements.

detect last foreach loop iteration

Supposing that I have some foreach loop like this:
Set<String> names = new HashSet<>();
//some code
for (String name: names) {
//some code
}
Is there a way to check inside foreach that the actual name is the last one in Set without a counter? I didn't found here some question like this.
For simplicity and understandability, imo, would do:
Set<String> names = new HashSet<>();
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
//Do stuff
if (!iterator.hasNext()) {
//last name
}
}
Also, it depends on what you're trying to achieve. Let's say you are implementing the common use case of separating each name by coma, but not add an empty coma at the end:
Set<String> names = new HashSet<>();
names.add("Joao");
names.add("Pereira");
//if the result should be Joao, Pereira then something like this may work
String result = names.stream().collect(Collectors.joining(", "));
Other answears are completely adequate, just adding this solution for the given question.
Set<String> names = new HashSet<>();
//some code
int i = 0;
for (String name: names) {
if(i++ == names.size() - 1){
// Last iteration
}
//some code
}
There isn't, take a look at How does the Java 'for each' loop work?
You must change your loop to use an iterator explicitly or an int counter.
If you are working with a complex object and not just a plain list/set the below code might help. Just adding a map function to actually get the desired string before you collect.
String result = violations.stream().map(e->e.getMessage()).collect(Collectors.joining(", "));
Yes, there is a way to check it inside of foreach, by use of a counter:
Set<String> names = new HashSet<>();
int i = names.size() - 1;
for (String name: names) {
if (i-- == 0) {
// some code for last name
}
//some code
}
Consider, names.size() is called only one time outside of the loop. This makes the loop faster than processing it multiple times within the loop.
There is no build in method to check if the current element is also the last element. Besides that you are using a HashSet which does not guarantee the return order. Even if you want to check it e.g. with an index i the last element could always be a different one.
A Set does not guaranty order over of items within it. You may loop through the Set once and retrieve "abc" as the "last item" and the next time you may find that "hij" is the "last item" in the Set.
That being said, if you are not concerned about order and you just want to know what the arbitrary "last item" is when observing the Set at that current moment, there is not built in way to do this. You would have to make use of a counter.
.map(String::toString) from the answer above is redundant, because HashSet already contains String values. Do not use Set to concatenate strings because the order is not assured.
List<String> nameList = Arrays.asList("Michael", "Kate", "Tom");
String result = nameList.stream().collect(Collectors.joining(", "));
There is an easy way you can do this throw one condition.
consider this is your array:
int odd[] = {1,3,5,7,9,11};
and you want to print it all in one line with " - " hyphen between them except the last one.
for(int aa:odd) {
System.out.print(aa);
if(odd[odd.length - 1] != aa)
System.out.print(" - ");
}
this condition
if( odd[odd.length - 1] != aa )
will check if you aren't in the last element so you can still add " - ", otherwise you will not add it.
List<String> list = Arrays.asList("1", "2", "3");
for (String each : list) {
if (list.indexOf(each) == (list.size() - 1)) {
System.out.println("last loop");
}
}
Note: Set is NOT an ordered collection.

Java Collection, Set, Map or Array to hold unique sorted non blank strings

I am fairly new to java and would like a container that I can use to hold strings that are not empty and have them sorted.
So far, I have mostly been using ArrayList, but this seems a bit limited for this case.
Thanks
Use TreeSet or TreeMap, depending on your requirements. Both are collections that accept unique elements and keep them sorted.
A Set is what you want, as the items in it have to be unique.
As the Strings should be sorted you'll need a TreeSet.
As for the non blank Strings you have to override the insertion methods like this:
Set<String> sortedSetOfStrings = new TreeSet<String>() {
#Override
public boolean add(String s) {
if(s.isEmpty())
return false;
return super.add(s);
}
};
EDIT: Simplified thanks to Peter Rader's comment.
Thanks for all the help. Here is what I eventually came up with, using TreeSet and apache commons StringUtils. My Input is a CSV String so, I didn't use the check on the input.
String csvString = "Cat,Dog, Ball, Hedge,, , Ball, Cat"
String[] array = StringUtils.split((String) csvString, ",");
for (int i = 0; i < array.length; i++)
{
array[i] = array[i].trim(); //Remove unwanted whitespace
}
set = new TreeSet<String>(Arrays.asList(array));
set.remove(""); //Remove the one empty string if it is there
set now contains: Ball,Cat,Dog,Hedge

Java - Checking if an ArrayList of String are in alphabetical order

I have an ArrayList called account which contains Strings. I'm trying to write a method that checks if they are in order and returns true or false based on whether they are in order or not.
How would you go about this? I've already tried checking the initial chracter with a for-loop but it went terribly wrong. I created a new ArrayList and set it equal to the original, then sorted it and compared them but since they contained the same data it always came back true.
Just an extra quick question, since I'm doing this for Strings, how would you check if some numbers were in ascending/descending order? Throught the same principal?
Thankyou!
Try this (assuming you want to compare the strings using their natural ordering, of course):
String previous = ""; // empty string: guaranteed to be less than or equal to any other
for (final String current: thelist) {
if (current.compareTo(previous) < 0)
return false;
previous = current;
}
return true;
This is due to the fact that String implements Comparable<String>, and the comparison will be done using the strings' natural ordering.
If you don't mind using external library (Guava) Ordering will do:
boolean isSorted = Ordering.natural().isOrdered(list);
This will do for String and other Comparables. If you are check ordering of some custom type, use any of the static factory methods in the Ordering class or subclass it.
Edit for case-insensitive ordering use:
boolean isSorted = Ordering.from(String.CASE_INSENSITIVE_ORDER).isOrdered(list);
I think a for loop would be suitable for this. The approach I would take would be to check each word against the previous and see if they are in the correct alphabetical ordering. Best case this is O(2) for determining that the list is out of order, worst case O(n) for telling you that the list is in order.
Edit: fge's answer above outlines the code for approach described.
Use the sort method of Collection class :
List<String> list = new ArrayList<String>();
//Add Elements
Collections.sort(list);
Sorts the specified list into ascending order, according to the
natural ordering of its elements.
ArrayList<String> initial = // smth
ArrayList<String> copy = // copy initial list here
Collections.sort(initial);
return initial.equals(copy);
Just use a loop and check if they are in order:
boolean isSorted = true;
for(int i = 0; i < list.size() - 1; i++) {
// current String is > than the next one (if there are equal list is still sorted)
if(list.get(i).compareToIgnoreCase(list.get(i + 1)) > 0) {
isSorted = false;
break;
}
}

Categories

Resources