New ArrayList with same values - java

I have an ArrayList:
ArrayList<Integer> example = new ArrayList<Integer>();
example.add(1);
example.add(1);
example.add(2);
example.add(3);
example.add(3);
So I want to make others three ArrayLists containing in which one the same values (where there is just one value the ArrayList would have just the one).
Is that possible?

Here's an approach to filtering out the elements, implemented: using a generic Map (in a generic class) to encapsulate the values.
The key is the object we want, and the value is determined as follows:
If the key never existed, we have a list with at most one element, which is the same as the key;
If the key has existed prior, we have a list with at least one element, which is the same as the key.
Here's how it's laid out. You instantiate it with the type of object you want to split.
public class UniqueSplitter<T> {
public Map<T, List<T>> filterOutElements(final List<?> theCandidateList) {
final Map<T, List<T>> candidateMap = new HashMap<>();
for(Object element : theCandidateList) {
if(candidateMap.containsKey(element)) {
candidateMap.get(element).add((T) element);
} else {
final List<T> elementList = new ArrayList<>();
elementList.add((T) element);
candidateMap.put((T)element, elementList);
}
}
return candidateMap;
}
}

Related

How to sort inner list which is a value of a map in Java?

It's more of a Java question (although I'm using Firebase). I'm trying to understand what's best way to sort a list. I'm trying to create the following map:
Map<Character,List<QueryDocumentSnapshot>> docs;
In order to build this map, I iterate over the documents in my collection, get the first letter of each one and insert the document into the list where the key is the letter.
The code:
for (QueryDocumentSnapshot current_document : value) {
char letter = getFirstLetter(current_document.getString("type"));
List<QueryDocumentSnapshot> list = docs.get(letter);
if (list == null) {
list = new ArrayList<>();
list.add(current_document);
docs.put(letter, list);
} else {
list.add(current_document);
}
}
In order to make the docs map sorted, I use TreeMap:
docs = new TreeMap<>();
But how can I make the list of documents be sorted by the field type (String)?
EDIT Sorry for not mentioning it, value is of type QuerySnapshot (firebase). Also I'm using Android's Java API 16 (which means I don't have java 8).
If you can use TreeSet instead of ArrayList, it can look like this. More you can find here: https://stackoverflow.com/a/8725470/4228138
Map<Character,Set<QueryDocumentSnapshot>> docs;
...
Comparator<QueryDocumentSnapshot> comparator = new Comparator<QueryDocumentSnapshot>() {
#Override
public int compare(QueryDocumentSnapshot o1, QueryDocumentSnapshot o2) {
return o1.getString("type").compareTo(o2.getString("type"));
}
};
for (QueryDocumentSnapshot currentDocument : value) {
char letter = getFirstLetter(currentDocument.getString("type"));
Set<QueryDocumentSnapshot> documents = docs.get(letter);
if (documents == null) {
documents = new TreeSet<>(comparator);
documents.add(currentDocument);
docs.put(letter, documents);
} else {
documents.add(currentDocument);
}
}
Create a Comparator and apply it to each List in the map. Since you are not changing the actual List reference you can sort in place. Note that I presumed that "type" returned a String. This may need to be changed.
Also, TreeMap has nothing to do with sorting the values. That would only sort the keys to the map.
Comparator<QueryDocumentSnapshot> comp = new CompareByType();
for (List<QueryDocumentSnapshot> list : docs.values()) {
Collections.sort(list,comp);
}
Here is the Comparator class
class CompareByType implements Comparator<QueryDocumentSnapshot> {
public int compare(QueryDocumentSnapshot a, QueryDocumentSnapshot b) {
String a = QueryDocumentSnapshot.getString("type");
String b = QueryDocumentSnapshot.getString("type");
return a.compareTo(b);
}
}
And here is a slight mod to your map creation. You don't need the else clause because list will always have a valid list when it is time to add the document.
for (QueryDocumentSnapshot current_document : value) {
char letter = getFirstLetter(current_document.getString("type"));
List<QueryDocumentSnapshot> list = docs.get(letter);
if (list == null) {
list = new ArrayList<>();
docs.put(letter, list);
}
// At this point you will always have a list to access.
// you can add the current document here
list.add(current_document);
}
The simplest way is to sort all QueryDocumentSnapshots before they are classified by first key. If the collection is sorted before, then each particular list will be sorted as well.
Hence, add
Collections.sort(value, Comparator.comparing(q -> q.getString("type")));
before the code you posted (I assume value a List, for general collection change it to stream sorting).
You can
Let the QueryDocumentSnapshot implement Compareableable<QueryDocumentSnapshot>. So it will use your implementation to sort the entries.
Provide a Comparator to the TreeMap constructor: TreeMap(Comparator<? super K> comparator)
The comparator can look like this:
(o1, o2) -> o1.getString("type").compareTo(o2.getString("type"))

List inside Redis Hash on Java

I'm using Spring with Redis and I am working with a list inside a hash. Everything works great on a single thread, problems come when I have to update list value with more than one instances.
Here is my code to put and get value from Hash:
public void put(String hashName, int key , List<myObj> myList) {
redis.opsForHash().put(hashName, String.valueOf(key), myList);
}
public List<myObj> get(String hashName, string key) {
Object map = redis.opsForHash().get(hashName,key);
if (map==null) {
log.info("no keys found");
return new ArrayList<myObj>();
}
List<myObj> myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
return myList;
}
What I do to perform update is:
List<myObj> myList= hash.get(hashName,key);
myList.add(obj);
hash.put(hashName, key, myList);
When there is more than one instance I occur in race condition. Is there a way to update list values in an atomic way?
Your current implementation is not good, because in the put() you update the whole list. In case many threads want to add a single element to the list they first obtain the current list, then add an element, then put new list. Each thread will override the result of the previous one, the last one wins. Usage of synchronized doesn't matter here.
Solution
Don't replace the whole list. Instead, add a single element to the list. Remove the method put() and add a new one like following:
public synchronized void add(String hashName, int key, myObj element) {
List<myObj> myList;
Object map = redis.opsForHash().get(hashName,key);
if (map != null) {
myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
} else {
myList = new ArrayList<myObj>();
}
myList.add(element);
redis.opsForHash().put(hashName, String.valueOf(key), myList);
}
Besides make sure there are no attempts to modify the list directly and that the only way to add elements is to use your method add(). Use Collections.unmodifiableList():
public List<myObj> get(String hashName, string key) {
Object map = redis.opsForHash().get(hashName,key);
if (map==null) {
log.info("no keys found");
return new ArrayList<myObj>();
}
List<myObj> myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
return Collections.unmodifiableList(myList);
}

Method put() in java Map of type <<String>,List<String>>

How can I put in a map of above type. I do not want to overwrite existing mapping.
So far my code is:
public class Store {
Map<String, List<String>> items;
public Store(){
items = new HashMap<String, List<String>>();
}
public boolean containsKey(String key) {
return items.containsKey(key);
}
public void put(String key, String item) {
List<String> myList = new ArrayList<>();
if (myList == null) {
myList = new ArrayList<String>();
items.put(key, item);
}
}
}
I stopped here because I received an error message stating "change the item type to list String from String". I can not figure out if I am doing something wrong.
Here, double wrong:
List<String> myList = new ArrayList<>();
if (myList == null) {
myList = new ArrayList<String>();
items.put(key, item);
}
myList will never be null, you just assigned a list to it! And item is just a single string, so you shouldn't use it as value for a map that expects lists of strings as value!
You go:
List<String> myList = items.get(key);
if (myList == null) {
myList = new ArrayList<String>();
}
myList.add(item);
items.put(key, myList);
instead.
Meaning: first you check if you already have a list for that key. If not, you create an empty one. Then you add your new item to the (potentially new) list. Before finally putting the list into the map (it could be already there, but then you just overwrite that information with "itself").
And if you want to know how the "pros" solve this problem, have a look at this questions and the answers I received upon asking it.
Or use Map.computeIfAbsent() that is designed for this requirement : add a new entry if not existing mapping for a specific key and getting the value for (the new one or the existing) :
items.computeIfAbsent(key, k -> new ArrayList<>())
.add(item);

How to load a list from a list inside an object in Java

I have a list of objects, and inside these objects I have another list. I would like to know if there's a simple way to load a list of those lists inside the object. I want to choose a parameter from the object (userCode for example), and I want that list to return all the lists from all the objects with the matching userCode.
If anyone could help me, I'll be forever grateful.
Thank you
Well the most straight forward way of iterating should be fine here. Just loop through the list and get the lists from the objects and add them to another list. below is a sample template.
List<List<T>> listOfLists = new ArrayList<>();
for (Obj o : listOfObjects){
listOfLists.add(o.list);
}
Let assume you have populated a list of lists somewhere like this:
List<List<Object>> list1 = new ArrayList<List<Object>>();
for(List<Object> list : list1){
List<Object> list2 = new ArrayList<Object>();
list.add(list2);
}
Then you could create something like this to find your object:
List<List<Object>> find = new ArrayList<List<Object>>();
for(List<Object> list : list1){
for(int i=0;i<list.size();i++){
if(list.get(i).toString().equals("userCode")){
find.add(list);
break;
}
}
}
return find;
Note that I assumed an Object you should put your condition in the if statment.
Start with some object that has a userCode and list fields:
class X {
private int userCode;
private List<Y> list;
int getUserCode(){ return userCode; }
List<Y> getList() { return list; }
}
and assume we've got a list of these guys:
List<X> listOfX;
What you want is covert each X in the list to an entry in a map. Here's a simple function that converts of list of X's to a Map
Map<Integer, List<Y>> buildMap(List<X> list) {
Map<Integer, List<Y>> map = new HashMap<Integer, ArrayList<Y>>();
for(X x:list) {
map.put(x.getUserCode(), x.getList());
}
return map;
}
The keys in the map are the userCode's from your list of X's and the values are X's list fields:
List<Y> listOfY = map.get(someUserCode);

How to have Java method return generic list of any type?

I would like to write a method that would return a java.util.List of any type without the need to typecast anything:
List<User> users = magicalListGetter(User.class);
List<Vehicle> vehicles = magicalListGetter(Vehicle.class);
List<String> strings = magicalListGetter(String.class);
What would the method signature look like? Something like this, perhaps(?):
public List<<?> ?> magicalListGetter(Class<?> clazz) {
List<?> list = doMagicalVooDooHere();
return list;
}
private Object actuallyT;
public <T> List<T> magicalListGetter(Class<T> klazz) {
List<T> list = new ArrayList<>();
list.add(klazz.cast(actuallyT));
try {
list.add(klazz.getConstructor().newInstance()); // If default constructor
} ...
return list;
}
One can give a generic type parameter to a method too. You have correctly deduced that one needs the correct class instance, to create things (klazz.getConstructor().newInstance()).
No need to even pass the class:
public <T> List<T> magicalListGetter() {
return new ArrayList<T>();
}
Another option is doing the following:
public class UserList extends List<User>{
}
public <T> T magicalListGetter(Class<T> clazz) {
List<?> list = doMagicalVooDooHere();
return (T)list;
}
List<User> users = magicalListGetter(UserList.class);
`
Let us have List<Object> objectList which we want to cast to List<T>
public <T> List<T> list(Class<T> c, List<Object> objectList){
List<T> list = new ArrayList<>();
for (Object o : objectList){
T t = c.cast(o);
list.add(t);
}
return list;
}
You can use the old way:
public List magicalListGetter() {
List list = doMagicalVooDooHere();
return list;
}
or you can use Object and the parent class of everything:
public List<Object> magicalListGetter() {
List<Object> list = doMagicalVooDooHere();
return list;
}
Note Perhaps there is a better parent class for all the objects you will put in the list. For example, Number would allow you to put Double and Integer in there.
Something like this
publiс <T> List<T> magicalListGetter(Class<T> clazz) {
List list = doMagicalVooDooHere();
return list;
}
You can simply cast to List and then check if every element can be casted to T.
public <T> List<T> asList(final Class<T> clazz) {
List<T> values = (List<T>) this.value;
values.forEach(clazz::cast);
return values;
}
Given some legacy code that returns an untyped List
List list = database.GetCustomers(); //legacy code returns untyped list
we will use a helper function:
public static <T> #NotNull List<T> castList(final #NotNull Iterable sourceList)
{
List<T> result = new ArrayList<>();
for (Object o : sourceList)
result.add((T)o);
return result;
}
to convert the returned list to a generic typed List<T>:
List<Customer> = castList(database.GetCustomers()); //cast the list the appropriate type
Why Java doesn't have extension methods is quite beyond me.
I'm pretty sure you can completely delete the <stuff> , which will generate a warning and you can use an, # suppress warnings. If you really want it to be generic, but to use any of its elements you will have to do type casting. For instance, I made a simple bubble sort function and it uses a generic type when sorting the list, which is actually an array of Comparable in this case. If you wish to use an item, do something like: System.out.println((Double)arrayOfDoubles[0] + (Double)arrayOfDoubles[1]); because I stuffed Double(s) into Comparable(s) which is polymorphism since all Double(s) inherit from Comparable to allow easy sorting through Collections.sort()
//INDENT TO DISPLAY CODE ON STACK-OVERFLOW
#SuppressWarnings("unchecked")
public static void simpleBubbleSort_ascending(#SuppressWarnings("rawtypes") Comparable[] arrayOfDoubles)
{
//VARS
//looping
int end = arrayOfDoubles.length - 1;//the last index in our loops
int iterationsMax = arrayOfDoubles.length - 1;
//swapping
#SuppressWarnings("rawtypes")
Comparable tempSwap = 0.0;//a temporary double used in the swap process
int elementP1 = 1;//element + 1, an index for comparing and swapping
//CODE
//do up to 'iterationsMax' many iterations
for (int iteration = 0; iteration < iterationsMax; iteration++)
{
//go through each element and compare it to the next element
for (int element = 0; element < end; element++)
{
elementP1 = element + 1;
//if the elements need to be swapped, swap them
if (arrayOfDoubles[element].compareTo(arrayOfDoubles[elementP1])==1)
{
//swap
tempSwap = arrayOfDoubles[element];
arrayOfDoubles[element] = arrayOfDoubles[elementP1];
arrayOfDoubles[elementP1] = tempSwap;
}
}
}
}//END public static void simpleBubbleSort_ascending(double[] arrayOfDoubles)

Categories