I want to shuffle an Arraylist and never bring the same result up again.
How do I do that with Collections.shuffle(myList);?
If this is answer is posted somewhere else please me know.
EDIT
Here is how I am displaying my result
textView.setText(myList.get(0));
Collections.shuffle does not provide that functionality. You need to do a separate deduplication step. A Set would provide that function.
Set s = new HashSet(myList.size());
s.addAll(myList);
List shuffledList = new ArrayList(s.size());
shuffledList.addAll(s)
// Since items come out of a set in an undefined order, using shuffledList
// in this state may suit your needs. otherwise go ahead and shuffle it too
Collections.shuffle(shuffledList)
return shuffledList;
Here is a more advanced question on deduplication.
Collections.shuffle will just shuffle the list passed. Its not maintaining any previous state. So if you want to avoid duplicate you'll have to keep a state of previously generated list and compare. Alternatively you could find all possible combination and the access that list one by one. Google Guava library has methods to find combinations. Collections2.permutations(myList) e.g.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.common.collect.Collections2;
public class Shuffle {
public static void main(String args[]) {
List<String> myList = new ArrayList<String>(Arrays.asList(new String[] {"a", "b", "c"}));
for(List<String> list : Collections2.permutations(myList)){
System.out.println(list);
}
}
}
This will give all non-repeating shuffles.
You could create an additional list that stores previously used items. Each time you get an item, you can check if it has already been used (and if so, skip it). This way, you can preserve the original items chances of being used. If you have 10 A's, and a B, and you shuffle them, you have a higher chance of the A showing up first...etc. If you do not want this functionality, than I recommend using a set.
ArrayList<String> used = new ArrayList<String>();
ArrayList<String> items = getItems();
Collections.shuffle(items);
public String getItem() {
if(items.length == 0)
return null;
item = items.remove(0);
if(used.contains(item))
return getItem();
return used.add(item)
}
In the case of using a set
HashSet<String> items = new HashSet<String>(getItems());
Collections.shuffle(items);
public String getItem() {
return items.remove(0);
}
If I understand you correctly you just want to display a random value of a list, in this case use that (no need to shuffle the whole list):
int rand = (int)(array.size()*Math.random());
textView.setText(myList.get(rand));
EDIT:
Use this function with a global tmp variable:
private List<String> tmpList = new ArrayList<String>();
private String getRandom(List<String> myList){
if (tmpList.size()<=0) tmpList = new ArrayList<String>(myList);
int rand = (int)(tmpList.size()*Math.random());
return tmpList.remove(rand);
}
and set the value as:
textView.setText(getRandom(myList));
Thank you for all the ideas and suggestions!
My issue was silly.
textView.setText(myList.get(order++)); fixed it!
Related
Basically I receive a 2 big data lists from 2 different database, the list looks like this:
List 1:
=============
A000001
A000002
A000003
.
.
A999999
List 2:
=============
121111
000111
000003
000001
.
.
I need to compare two list and find out each data which is in List 1 is available in List 2 (after appending some standard key to it), so that and if it is available put it in 3rd list for further manipulation. As an example A000001 is available in List 1 as well as in List 2 (after appending some standard key to it) so I need to put it in 3rd list.
Basically I have this code, it does like this for each row in List 1, I'm iterating through all data in List 2 and doing comparison. (Both are array list)
List<String> list1 = //Data of list 1 from db
List<String> list2 = //Data of list 2 from db
for(String list1Item:list1) {
for(String list2Item:list2) {
String list2ItemAfterAppend = "A" + list2Item;
if(list1Item.equalsIgnoreCase(list2ItemAfterAppend)) {
//Add it to 3rd list
}
}
}
Yes, this logic works fine, but I feel this is not efficient way to iterate list. After putting timers, it's taking 13444 milliseconds on average for 2000x5000 list of data. My question is, is there any other logic you people can think of or suggest me to improve the performance of this code?
I hope I'm clear, if not please let me know if I can improve question.
You can order both list, then using only one loop iterate on both value, switching which index increments depending on which value is the biggest. Something like:
boolean isWorking = true;
Collections.sort(list1);
Collections.sort(list2);
int index1 = 0;
int index2 = 0;
while(isWorking){
String val1 = list1.get(index1);
String val2 = "A" + list2.get(index2);
int compare = val1.compareTo(val2)
if(compare == 0){
list3.add(val1);
index1++;
index2++;
}else if (compare > 0){
val2++;
}else{ // if(compare < 0)
val1++;
}
isWorking = !(index1 == list1.size() || index2 == list2.size() );
}
Be carefull about what kind of List you're using. The get(int i) on LinkedList is expensive, whereas it is not on an ArrayList. Also, you might want to save list1.size() and list2.size(), I dont't think it calcluates it everytime, but chek it. I'm not sure if it's really usefull/efficient, but you can initialise list3 with the size of the smallest of both list (taking into acount the loadFactor, look up for it), so list3 doesnt have to resize everytime.
The code above is not tested (maybe switch val1++ and val2++), but you get the idea. I believe it's faster than yours (because it's O(n+m) rather than O(n*m) but I'll let you see (both sort() and compareTo() will add some time compared to your method, but normally it shouldn't be too much). If you can, use your RDBMS to sort both list when you get them (so you don't have to do it in the Java code)
I think the problem is how big the list is and how much memory you have.
For me for under 1 million records, I will use a HashSet to make it faster.
Code may like:
Set<String> set1 = //Data of list 1 from db, when you get the data you make it a Set instead of a List. HashSet is enough for you to use.
List<String> list2 = //Data of list 2 from db
Then you just need to:
for(String list2Item:list2) {
if(set1.contains("A" + list2Item) {
}
}
Hope this can help you.
You can use intersection method from apache commons. Example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
public class NewClass {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("A000001","A000002","A000003");
List<String> list2 = Arrays.asList("121111","000111","000001");
List<String> list3 = new ArrayList<>();
list2.stream().forEach((s) -> {list3.add("A"+s);});
Collection<String> common = CollectionUtils.intersection(list1, list3);
}
}
You could try to use the Stream API for this, the code to create the new list with Streams is very concise and straightforward and probably very similar in performance:
List<String> list3 = list2.stream()
.map(s->"A"+s)
.filter(list1::contains)
.collect(Collectors.toList());
If the list are big, you could try to process the list in parallel and use multiple threads to process the list. This may or may not improve the performance. Doing some measures its important to check if processing the list in parallel is actually improving the performance.
To process the stream in parallel, you only need to call the method parallel on the stream:
List<String> list3 = list2.stream()
.parallel()
.map(s->"A"+s)
.filter(list1::contains)
.collect(Collectors.toList());
Your code is doing a lot of String manipulation, 'equalsIgnoreCase' convert the Characters to upper/lower case. This is being executed in your inner loop and the size of your list is 5000x2000, so the String manipulation is being done millions of times.
Ideally, get your Strings in either upper or lower case from the database and avoid the conversion inside the inner loop. If this is not possible, probably converting the case of the String at the beginning improves the performance.
Then, you could create a new list with the elements of one of the lists and keep all the elements present in the other list, the code with the uppercase conversion could be:
list1.replaceAll(String::toUpperCase);
List<String> list3 = new ArrayList<>(list2);
list3.replaceAll(s->"A"+s.toUpperCase());
list3.retainAll(list1);
I'm having so much trouble with a program I'm working.
The program is supposed to print out the elements of an ordered linked list (as in there are no setters available for the list) in alphabetical order. Here's what I have:
GOrderedList is the node, Event is the value. I had the idea to attempt to find the words and place them in an arraylist alphabetically.
public static ArrayList <String> sortEvents (GOrderedList <Event> C){
//create arraylist
ArrayList <String> sortedList = new ArrayList <String>();
while (C.getNext()!=null){
GOrderedList <Event> first = C.getNext();
String highest = first.getValue().getname();
while (first.getNext()!=null){
if (first.getNext().getValue().getname().compareTo(highest)<0){
highest=C.getNext().getValue().getname();
}
first=first.getNext();
}
sortedList.add(highest);
C = C.getNext();
}
This is producing the list -which is encouraging - but it is out of order. I had the idea of placing the elements in the new ArrayList in alphabetical order. I could place the items in the ArrayList and then sort it, but I would rather not do that.
You can use the comparator to sort it .Like below.
public static ArrayList<String> sortEvents(GOrderedList<Event> C) {
// create arraylist
ArrayList<String> sortedList = new ArrayList<String>();
while (true) {
GOrderedList<Event> first = C.getNext();
if (first == null) {
break;
}
String highest = first.getValue().getname();
sortedList .add(highest);
}
Collections.sort(sortedList , new Comparator<String>() {
public int compare(String f1, String f2) {
return f1.toString().compareTo(f2.toString());
}
});
return sortedList ;
};
There are a few issues with the code:
Calling getNext() in the while loop will increment and skip a value each time. You probably need to call a hasNext() method.
Each iteration of the outer loop needs to add its element in the proper position. As written, the value added is always going to be at the end.
As previously mentioned there are standard ways to do this, but my assumption is that you need to do this as an exercise. If not, use a Comparator. String's natural comparison may give you exactly what you want.
I'm trying to invert an arrayList of votes in order to yield preference (i.e. a vote of 2,4,1,3, after inverted is 3,1,4,2. the indexed preference is 3). I believe this can be done with Collections but the list is of difference type (type Vote). Just need some guidance on how i could sort this preference order when i cant use Collections methods on Vote.
public Vote invertVote() {
VoteList invVote = (VoteList) ((Vote) vote).copyVote();
Iterator<Integer> iter = invVote.iterator();
while(iter.hasNext()){
iter.next();
Collections.reverse(invVote);
}
return invVote;
}
Note Vote is a collection of integers representing a single vote. VoteList implements Vote. copyVote() is used to create a deep copy of the vote in order to not alter it and return a new Vote object. Still stuck the error during Collections.reverse(invVote)
Yes this can be done using collection you just need to call the method Collections.reverse...
public static void reverse(List<?> list)
Reverses the order of the elements in the specified list.
This method
runs in linear time.
Example:
public static void main(String[] args) {
Random rnd = new Random();
List<Integer> myInteger = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
myInteger.add(rnd.nextInt(10));
}
// the list
System.out.println(myInteger);
// the list sorted
Collections.sort(myInteger);
System.out.println(myInteger);
// the list inverted
Collections.reverse(myInteger);
System.out.println(myInteger);
}
in your case use the class Votes instead of integer and make the class to implement the comparable interface where you define the sorting logic....
You can use Collections.reverse(list); check documentation.
Guys i wanna ask about the best way to iterate collection classes ??
private ArrayList<String> no = new ArrayList<String>();
private ArrayList<String> code = new ArrayList<String>();
private ArrayList<String> name = new ArrayList<String>();
private ArrayList<String> colour = new ArrayList<String>();
private ArrayList<String> size = new ArrayList<String>();
// method for finding specific value inside ArrayList, if match then delete that element
void deleteSomeRows(Collection<String> column, String valueToDelete) {
Iterator <String> iterator = column.iterator();
do{
if (iterator.next()==valueToDelete){
iterator.remove();
}
}while(iterator.hasNext());
}
deleteSomeRows(no, "value" );
deleteSomeRows(code, "value" );
deleteSomeRows(name , "value");
deleteSomeRows(colour ,"value" );
deleteSomeRows(size , "value");
THE PROBLEM WITH CODES ABOVE IS THAT IT TAKES AMOUNT OF TIME JUST TO ITERATE EACH OF THOSE CLASSES ? ANY SOLUTION TO MAKE IT FASTER ? pls help if u care :D..
You could simplify your code:
while column.contains(valueToDelete)
{
column.remove(valueToDelete);
}
You're not going to be able to speed up your ArrayList iteration, especially if your list is not sorted. You're stuck at O(n) for this problem. If you sorted it and inserted logic to binary search for the item to remove until it is no longer found, you could speed up access.
This next suggestion isn't directly related to the time it takes, but it will cause you problems.
You should never compare String objects for equality using the == operator. This will cause a comparison of their pointer values.
Use this instead:
if (iterator.next().equals(valueToDelete))
EDIT: The problem here is not the iteration. The problem is removing the elements from the ArrayList. When you remove the first element from an ArrayList, then all subsequent elements have to be shifted one position to the left. So in the worst case, your current approach will have quadratic complexity.
It's difficult to avoid this in general. But in this case, the best tradeoff between simplicity and performance can probably be achieved like this: Instead of removing the elements from the original list, you create a new list which only contains the elements that are not equal to the "valueToDelete".
This could, for example, look like this:
import java.util.ArrayList;
import java.util.List;
public class QuickListRemove
{
public static void main(String[] args)
{
List<String> size = new ArrayList<String>();
size = deleteAll(size, "value");
}
private static <T> List<T> deleteAll(List<T> list, T valueToDelete)
{
List<T> result = new ArrayList<T>(list.size());
for (T value : list)
{
if (!value.equals(valueToDelete))
{
result.add(value);
}
}
return result;
}
}
If you want to modify the collection while iterating them then you should use Iterators, otherwise you can use the for-each loop.
For -each :
// T is the type f elements stored in myList
for(T val : myList)
{
// do something
}
Try putting a break after you find the element to delete.
Hello im rather stuck on this part of my java programming work. I have done what i think is right for this question but im unsure if it is right as the next question asks to add 4 different strings into two different sub-lists (and thats where im getting stuk).
This is the first question:
Create a variable called balancedThings of type ArrayList of ArrayLists of Strings and add a method balancedInit() that instantiates the balancedThings variable by creating a new ArrayList > object and that also creates two new ArrayList objects and adds these to the balancedThings list.
this is the second question:
Add a method balancedCreation() that adds the strings “sword” and “map” to the first of the two sub-lists, and the strings “shield” and “bottle” to the second sub-list.
This is my answer:
void balancedInit()
{
balancedThings = new ArrayList<>();
balancedThings.add(0, "SubListOne");
balancedThings.add(1, "SubListTwo");
}
Can anyone explain if this is right for the question and where i should go next in order to add into sublists?
I think you just need to build the solution from the bottom up. Before worrying about the list of lists, worry about the individual lists first.
So first, you just want a list of strings. You can do that like this:
private static ArrayList<String> firstSublist() {
ArrayList<String> list = new ArrayList<>();
list.add("sword");
list.add("map");
return list;
}
ArrayList is your list, and the String in angle brackets tells you what type is going to be in the list. Then you add the actual strings. Do this for the other sublist too.
Then when you have a way to make your little lists, time to compose the big one:
private static void balancedCreation(ArrayList<ArrayList<String>> listOfLists) {
listOfLists.add((firstSublist()));
listOfLists.add((secondSublist()));
}
Here you have a list of lists. I know all the angle brackets can be confusing with something like ArrayList<ArrayList<String>>, but just remember to look at it a little at a time from the inside out.
So with the big list, you are just adding a thing--exactly like the sublists. As long as you take care of business at the simpler level, building up to the top level is no sweat.
In the end, main looks like this
public static void main(String[] args) {
ArrayList<ArrayList<String>> listOfLists = new ArrayList<>();
balancedCreation(listOfLists);
}
Hope this helps.
you want to add an ArrayList of Strings in an ArrayList :
public void balancedInit() {
ArrayList<ArrayList<String>> balancedThings = new ArrayList<ArrayList<String>>();
ArrayList<String> subListOne = new ArrayList<String>();
ArrayList<String> subListTwo = new ArrayList<String>();
// add values to your Sub Lists then ...
balancedThings.add(subListOne); // this will be index 0 implicitly
balancedThings.add(subListTwo); // this will be index 1 implicitly
}
programmers prefer using polymorphism in Collections framework, like declaring the ArrayList as List, but this is not a good practice when it comes to Serialization
initialize andinstantiate the "SublistOne" and "SubListTwo" in the way you initialized the BalancedThings.
that should create the sublist.
void balancedInit()
{
ArrayList<ArrayList<String>> balancedThings = new ArrayList<ArrayList<String>>();
ArrayList<String> subLiostOne = = new ArrayList<String>();
ArrayList<String> subLiostTwo = = new ArrayList<String>();
subListOne.add(0,"sword");
subListOne.add(1,"map");
subListTwo.add(0,"shield");
subListTwo.add(1,"bottle");
balancedThings.add(0, subListOne);
balancedThings.add(1, subListTwo);
}
please mark the answer as helpful if it is helpful