Say I have two ArrayLists:
name: [Four, Three, One, Two]
num: [4, 3, 1, 2]
If I do: Arrays.sort(num), then I have:
name: [Four, Three, One, Two]
num: [1, 2, 3, 4]
Is there any way I can possibly do a sort on num and have it reflected in name as well, so that I might end up with:
name: [One, Two, Three, Four]
num: [1, 2, 3, 4]
? Please do help me out. I thought of Comparators and Objects, but barely know them at all.
You should somehow associate name and num fields into one class and then have a list of instances of that specific class. In this class, provide a compareTo() method which checks on the numerical values. If you sort the instances, then the name fields will be in the order you desire as well.
class Entity implements Comparable<Entity> {
String name;
int num;
Entity(String name, int num) {
this.name = name;
this.num = num;
}
#Override
public int compareTo(Entity o) {
if (this.num > o.num)
return 1;
else if (this.num < o.num)
return -1;
return 0;
}
}
Test code could be like this:
public static void main(String[] args) {
List<Entity> entities = new ArrayList<Entity>();
entities.add(new Entity("One", 1));
entities.add(new Entity("Two", 2));
entities.add(new Entity("Three", 3));
entities.add(new Entity("Four", 4));
Collections.sort(entities);
for (Entity entity : entities)
System.out.print(entity.num + " => " + entity.name + " ");
}
Output:
1 => One 2 => Two 3 => Three 4 => Four
Instead of sorting the actual arrays you can have an array with just indices
a[i] = i for i = 0..n
and you can sort this array based on your numeruc array with a custom comparator. e.g.
bool compare( int a, int b ) { return num[a] < num[b]; }
Thus you have both arrays sorted by using these indices.
If you don't have repeated elements, then you could just use a sorted Map like a TreeMap instead:
int[] num = {4, 3, 1, 2};
String[] name = {"Four", "Three", "One", "Two"};
TreeMap<Integer,String> sortedMap = new TreeMap<Integer,String>();
for (int i=0; i<num.length; i++) sortedMap.put(num[i], name[i]);
// Resulting sortedMap: {1=One, 2=Two, 3=Three, 4=Four}
If you do have repeated elements then this won't work because the keys of the map must be unique.
In some cases it doesn't make much sense to create a new class just to do multiple sorts based off a given list. I've created a function that does this, but I've posted the code in a another SO post so I wont repeat it. Below is an example of how to use it.
Usage
Here is an example of how you can use the function to sort multiple lists of arbitrary types:
// The key can be any type that implements Comparable, Dupes are allowed
List<Integer> key = Arrays.asList(4, 3, 1, 2, 1);
// List Types do not need to be the same
List<String> list1 = Arrays.asList("Four", "Three", "One", "Two", "One");
List<Character> list2 = Arrays.asList('d', 'c', 'a', 'b', 'a');
// Sorts key, list1, list2 using key as the sorting key.
keySort(key, key, list1, list2);
Output:
key: [1, 1, 2, 3, 4]
list1: [One, One, Two, Three, Four]
list2: [a, a, b, c, d]
Related
I am trying to add all subsequences of an array in an ArrayList. Below is my program where i am using recursion:
public class Subsequences {
public static void main(String[] args) {
int arr[] = {1,2,3};
List<List<Integer>> result = new ArrayList<>();
List<Integer> list = new ArrayList<>();
printSubsequences(0,arr,list,result);
System.out.println(result);
}
private static List<List<Integer>> printSubsequences(int i, int[] arr, List<Integer> list, List<List<Integer>> result) {
if(i>=arr.length){
result.add(list);
return result;
}
list.add(arr[i]); //take
printSubsequences(i+1,arr,list,result);
list.remove(list.size()-1); //not take
printSubsequences(i+1,arr,list,result);
return result;
}
}
The output of the following program is:
[[], [], [], [], [], [], [], []]
Why is my arraylist empty here? Can someone please explain?
You are modifing the same one inner list over and over again instead of adding new lists. Change
printSubsequences(i+1,arr,list,result);
to
printSubsequences(i+1,arr,new ArrayList<>(list),result);
to create a new list and copy the current elements to a new sublist
private static List<List<Integer>> printSubsequences(int i, int[] arr, List<Integer> list, List<List<Integer>> result) {
if(i>=arr.length){
result.add(list);
return result;
}
list.add(arr[i]); //take
printSubsequences(i+1,arr,new ArrayList<>(list),result);
list.remove(list.size()-1); //not take
printSubsequences(i+1,arr,new ArrayList<>(list),result);
return result;
}
When you just use a println statement, you are just printing the current state of your list for the current recursive step. You are adding and removing elements to and from the same list. Your list of lists contains 8 times the same list, so modifing one of them will reflect the change to each of them. To give you a simple example:
List<List<String>> result = new ArrayList<>();
List<String> sagarList = new ArrayList<>();
sagarList.add("Sagar");
sagarList.add("Balyan");
System.out.println("sagarList: " + sagarList);
//now let's add the same list multiple times to the result list
result.add(sagarList);
result.add(sagarList);
result.add(sagarList);
result.add(sagarList);
System.out.println("result before removing one element from sagarList: " );
System.out.println(result);
//lets make one change to the list
sagarList.remove(sagarList.size()-1);
System.out.println("result after removing one element from sagarList: ");
System.out.println(result);
output:
sagarList: [Sagar, Balyan]
result before removing one element from sagarList:
[[Sagar, Balyan], [Sagar, Balyan], [Sagar, Balyan], [Sagar, Balyan]]
result after removing one element from sagarList:
[[Sagar], [Sagar], [Sagar], [Sagar]]
If you look at your result list at the last step of your recursion the list is empty, that describes why all of your sublists were empty befor making the change:
[[1, 2, 3], [1, 2], [1, 3], [1], [2, 3], [2], [3], []]
because " list.remove(list.size()-1); " will clear the list finally
,and
the eight lists in the result are the same list
I want to loop over the same list to process possible combinations of that list. For example : From a list consisting [1,2,3] I want to get an ArrayList which looks like this: [[1,2], [1,3], [2,3]]
I am processing a list of nodes instead of integers. For now i am trying something like the following :
ArrayList<ArrayList<Node>> saveList = new ArrayList<ArrayList<Node>>();
for (Node n1 : nodes)
ArrayList<Node> saveList2 = new ArrayList<Node>();
for (Node n2 : nodes)
if n2.name == n1.name
continue;
saveList2.add(n1).add(n2);
if (!saveList.containsAll(saveList2))
then process graph;
else continue;
I don't process the same node and avoid the combination already processed. Is there a better solution ?
Using a combinatorics library may be a bit overkill in your case. Your task is indeed finding combinations of size 2, but the fact that the size is two simplifies it drastically.
A good old index-based for-loop does the trick here, with no check for duplicates necessary. Notice how the second loop starts from i + 1. Go over the algorithm in a scratchpad and you will see how this avoids duplicates.
List<List<Node>> pairs = new ArrayList<>();
for (int i = 0; i < nodes.size(); i++) {
for (int j = i + 1; j < nodes.size(); j++) {
pairs.add(Arrays.asList(nodes.get(i), nodes.get(j)));
}
}
If the task is not of academic nature or does not consist of implementing an algorithm, I would use a library and focus on the core of the task the application is supposed to solve. Such a library would be for example combinatoricslib3. Google guava or Apache commons certainly have similar methods. With combinatoricslib3 the solution to your issue above would be a one-liner:
Generator.combination(1,2,3)
.simple(2)
.stream()
.forEach(System.out::println);
Output:
[1, 2]
[1, 3]
[2, 3]
or something like:
List<List<String>> result = Generator.combination("FOO", "BAR", "BAZ")
.simple(2)
.stream()
.collect(Collectors.toList());
System.out.println(result);
to get
[[FOO, BAR], [FOO, BAZ], [BAR, BAZ]]
It works not only for primitive data types like ints or strings as shown above, you can also use your own custom objects and use a list of your objects as a parameter. Assuming you have a Node class:
public class Node {
String name;
// getter, setter, toString ...
}
List<Node> nodeList = List.of(new Node("node1"), new Node("node2"), new Node("node3"));
Generator.combination(nodeList)
.simple(2)
.stream()
.forEach(System.out::println);
Output:
[Node(name=node1), Node(name=node2)]
[Node(name=node1), Node(name=node3)]
[Node(name=node2), Node(name=node3)]
To use the lib add the dependency to your pom.xml or download the jar and add to classpath. mvn dependency:
<dependency>
<groupId>com.github.dpaukov</groupId>
<artifactId>combinatoricslib3</artifactId>
<version>3.3.2</version>
</dependency>
Try this.
static <T> List<List<T>> combinations(List<T> list, int n) {
int length = list.size();
List<List<T>> result = new ArrayList<>();
T[] selections = (T[])new Object[n];
new Object() {
void select(int start, int index) {
if (index >= n)
result.add(List.of(selections));
else if (start < length){
selections[index] = list.get(start);
select(start + 1, index + 1);
select(start + 1, index);
}
}
}.select(0, 0);
return result;
}
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3);
System.out.println(combinations(list, 2));
}
output:
[[1, 2], [1, 3], [2, 3]]
I have two ArrayLists array1 and array2.
In both ArrayLists there can be different numbers, but in array2 it's always just one number.
In an onClickListener I need the number of array2 to be deleted from array1.
For example:
ArrayList array1 = new Arraylist(2,1,4,6,3);
ArrayList array2 = new Arraylist(1);
Then I tried:
array1.remove(array2)
but nothing happens...
What is the best way to achieve that?
For Context:
I have three fragments, one where you can see your deck DeckKartenFragment and two where you can choose your card RadlerKarte and HopfentrunkKarte. I have two ImageViews, where you can put the chosen cards.
I want that each card can only be chosen once. For that I made two Arrays. One in which all chosen cards are deck.deck (Is stored in class deck) and one in which the current chosen card of the ImageView is deck1WelcheKarte.
//Check if card is already chosen//
if (deck.deck.contains(1) == true){
Toast.makeText(getActivity(), "example" , Toast.LENGTH_LONG).show();
deck.cardchosen.clear();
}
if (deck.deck.contains(1) == false){
deck.deck.add(1); //Add Card to deck//
deck.deck.removeAll(deck1WelcheKarte); //Remove card that was chosen before from deck//
deck1WelcheKarte.clear(); //Reset card that is chosen to current card//
deck1WelcheKarte.add(1);}}
Now if I chose my first card everything works fine, when I replace that card with a new one it still works. But when i replace that card again with my first card, the number for that first card seems to be still in deck, because my app goes to makeToast instead of add new card to deck...
for(int i : array2) {
array1.remove(i)
}
this way you dont have to chack if array2 contains any element, it also covers multiple elements
okey then try this code and copare it to yours:
public static void main(String[] args){
ArrayList<Integer> a = new ArrayList<>(6);
// ArrayList is kind of lacking right constructor so we have to insert values manually
for(int i : new int[]{1, 2, 3, 4, 5, 6}) {
a.add(i);
}
ArrayList<Integer> b = new ArrayList<>(1);
b.add(1);
// integer is important if we use int, it will remove by index
for(Integer i : b) {
a.remove(i);
}
System.out.println(a);
}
Following the previous answer, which is a good one, you have to change the type of your java.uti.ArrayList because Java Collections don't support primitive types.
Actually, when you try to add a primitive type element into the ArrayList, the value gets implicitly wrapped by an Object class of its own type, for example
This statement array1.add(1); -> It's same as -> array1.add(new Integer(1));
Here is an example to let you understand:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
int myArray[] = { 2, 1, 4, 6, 3 };
List<Integer> arrayList1 = new ArrayList();
for (int elem : myArray) {
arrayList1.add(elem);
}
List<Integer> arrayList2 = new ArrayList();
arrayList2.add(2);
System.out.println("array of int: " + Arrays.toString(myArray));
System.out.println("arrayList2 (List of " + arrayList2.get(0).getClass().getName() + " ): " + arrayList2);
System.out.println("Before remove - arrayList1: " + arrayList1);
for (Object a : arrayList2) {
System.out.println("Removing element (type " + a.getClass().getName() + "): " + a);
arrayList1.remove(a);
}
System.out.println("After remove - arrayList1" + arrayList1);
}
}
Output is:
array of int: [2, 1, 4, 6, 3]
arrayList2 (List of java.lang.Integer ): [2]
Before remove - arrayList1: [2, 1, 4, 6, 3]
Removing element (type java.lang.Integer): 2
After remove - arrayList1[1, 4, 6, 3]
As you see from the code, I just printed out the name of the class which is used when you add any int to the java.util.List of Object, and they actually get wrapped by java.lang.Integer class.
If I have a list with integers, is there a way to construct another list, where integers are summed if the difference to the head of the new list is below a threashold? I would like to solve this using Java 8 streams. It should work similar to the Scan operator of RxJava.
Example: 5, 2, 2, 5, 13
Threashold: 2
Result: 5, 9, 13
Intermediate results:
5
5, 2
5, 4 (2 and 2 summed)
5, 9 (4 and 5 summed)
5, 9, 13
Sequential Stream solution may look like this:
List<Integer> result = Stream.of(5, 2, 2, 5, 13).collect(ArrayList::new, (list, n) -> {
if(!list.isEmpty() && Math.abs(list.get(list.size()-1)-n) < 2)
list.set(list.size()-1, list.get(list.size()-1)+n);
else
list.add(n);
}, (l1, l2) -> {throw new UnsupportedOperationException();});
System.out.println(result);
Though it looks not much better as good old solution:
List<Integer> input = Arrays.asList(5, 2, 2, 5, 13);
List<Integer> list = new ArrayList<>();
for(Integer n : input) {
if(!list.isEmpty() && Math.abs(list.get(list.size()-1)-n) < 2)
list.set(list.size()-1, list.get(list.size()-1)+n);
else
list.add(n);
}
System.out.println(list);
Seems that your problem is not associative, so it cannot be easily parallelized. For example, if you split the input into two groups like this (5, 2), (2, 5, 13), you cannot say whether the first two items of the second group should be merged until the first group is processed. Thus I cannot specify the proper combiner function.
As Tagir Valeev observed, (+1) the combining function is not associative, so reduce() won't work, and it's not possible to write a combiner function for a Collector. Instead, this combining function needs to be applied left-to-right, with the previous partial result being fed into the next operation. This is called a fold-left operation, and unfortunately Java streams don't have such an operation.
(Should they? Let me know.)
It's possible to sort-of write your own fold-left operation using forEachOrdered while capturing and mutating an object to hold partial state. First, let's extract the combining function into its own method:
// extracted from Tagir Valeev's answer
void combine(List<Integer> list, int n) {
if (!list.isEmpty() && Math.abs(list.get(list.size()-1)-n) < 2)
list.set(list.size()-1, list.get(list.size()-1)+n);
else
list.add(n);
}
Then, create the initial result list and call the combining function from within forEachOrdered:
List<Integer> result = new ArrayList<>();
IntStream.of(5, 2, 2, 5, 13)
.forEachOrdered(n -> combine(result, n));
This gives the desired result of
[5, 9, 13]
In principle this can be done on a parallel stream, but performance will probably degrade to sequential given the semantics of forEachOrdered. Also note that the forEachOrdered operations are performed one at a time, so we needn't worry about thread safety of the data we're mutating.
I know that the Stream's masters "Tagir Valeev" and "Stuart Marks" already pointed out that reduce() will not work because the combining function is not associative, and I'm risking a couple of downvotes here. Anyway:
What about if we force the stream to be sequential? Wouldn't we be able then to use reduce? Isn't the associativity property only needed when using parallelism?
Stream<Integer> s = Stream.of(5, 2, 2, 5, 13);
LinkedList<Integer> result = s.sequential().reduce(new LinkedList<Integer>(),
(list, el) -> {
if (list.isEmpty() || Math.abs(list.getLast() - el) >= 2) {
list.add(el);
} else {
list.set(list.size() - 1, list.getLast() + el);
}
return list;
}, (list1, list2) -> {
//don't really needed, as we are sequential
list1.addAll(list2); return list1;
});
Java 8 way is define custom IntSpliterator class:
static class IntThreasholdSpliterator extends Spliterators.AbstractIntSpliterator {
private PrimitiveIterator.OfInt it;
private int threashold;
private int sum;
public IntThreasholdSpliterator(int threashold, IntStream stream, long est) {
super(est, ORDERED );
this.it = stream.iterator();
this.threashold = threashold;
}
#Override
public boolean tryAdvance(IntConsumer action) {
if(!it.hasNext()){
return false;
}
int next = it.nextInt();
if(next<threashold){
sum += next;
}else {
action.accept(next + sum);
sum = 0;
}
return true;
}
}
public static void main( String[] args )
{
IntThreasholdSpliterator s = new IntThreasholdSpliterator(3, IntStream.of(5, 2, 2, 5, 13), 5);
List<Integer> rs= StreamSupport.intStream(s, false).mapToObj(Integer::valueOf).collect(toList());
System.out.println(rs);
}
Also you can hack it as
List<Integer> list = Arrays.asList(5, 2, 2, 5, 13);
int[] sum = {0};
list = list.stream().filter(s -> {
if(s<=2) sum[0]+=s;
return s>2;
}).map(s -> {
int rs = s + sum[0];
sum[0] = 0;
return rs;
}).collect(toList());
System.out.println(list);
But I am not sure that this hack is good idea for production code.
I need your help in arraylist problem. I have 2 arraylist.
ArrayList<string> a = {"fruit=apple,grape,banana;nut=pistachio,chestnut,walnut,peanut;vegetable=broccoli,carrot,cabbage,tomato"}
Arraylist<String> b = {"1:1:2 2:1:2 2:3:4 3:4:4"}
Ok, array b is represent the food in a. lets say
1:1:2 means apple:nut:carrot ,
2:1:2 means grape:pistachio:carrot,
2:3:4 means grape:walnut:tomato and
3:4:4 means banana:peanut:tomato.
Currently I have no idea at all. Hopefully you guys can help me about the idea how to do this.
Thanks in advance
Well, you currently have several problems which are probably confusing the situation:
There is no such class ArrayList<string>, I guess you mean List<string>
Currently your lists consist of a single element, which is a comma / space delimited string. You probably want something more like this:
List fruit = new List(new string[] {"apple", "grape", "banana" });
List nut = new List(new string[] {"pistachio", "chestnut", "walnut", "peanut" });
List vegetable = new List(new string[] {"broccoli", "carrot", "cabbage", "tomato" });
This gives you a list where each element is a nut, fruit or vegetable respectively.
Also your second list should probably look more like this:
List<int[]> combinations = new List<int[]>(
new int[][]
{
new int[] {1, 1, 2},
new int[] {2, 1, 2},
new int[] {2, 3, 4},
new int[] {3, 4, 4},
});
I.e. conbinations is a list of combinations, where each combination consists of 3 integers - the index of each element in the list. (This is possibly a tad confusing and by no means the only option - ask if this bit isn't clear).
In face as arrays are 0-indexed in c#, in fact you probably want this instead:
List<int[]> combinations = new List<int[]>(
new int[][]
{
new int[] {0, 0, 1},
new int[] {1, 0, 1},
new int[] {1, 2, 3},
new int[] {2, 3, 3},
});
This at least makes your data easier to work with, so the only questions remaining are:
How do you get from what you have to the above? (I'll let you have a go at that yourself).
What is it that you are trying to do?
Try Below code it works as expected let me know it it does not fulfill use case.
public static List<String> fruits = new ArrayList<String>();
public static List<String> nuts = new ArrayList<String>();
public static List<String> vegitables = new ArrayList<String>();
/**
* #param args
* #throws ParseException
* #author Rais.Alam
*/
public static void main(String[] args) throws ParseException
{
fruits.add("apple");
fruits.add("grape");
fruits.add("banana");
nuts.add("pistachio");
nuts.add("chestnut");
nuts.add("walnut");
nuts.add("peanut");
vegitables.add("broccoli");
vegitables.add("carrot");
vegitables.add("cabbage");
vegitables.add("tomato");
System.out.println(getValue("1:1:2"));
System.out.println(getValue("2:1:2"));
System.out.println(getValue("2:3:4"));
System.out.println(getValue("3:4:4"));
}
public static String getValue(String key)
{
String returnString = "";
String[] arr = key.split(":");
returnString += fruits.get(Integer.parseInt(arr[0]) - 1) == null ? "" : fruits.get(Integer.parseInt(arr[0]) - 1) + ":";
returnString += nuts.get(Integer.parseInt(arr[1]) - 1) == null ? "" : nuts.get(Integer.parseInt(arr[1]) - 1) + ":";
returnString += vegitables.get(Integer.parseInt(arr[2]) - 1) == null ? "" : vegitables.get(Integer.parseInt(arr[2]) - 1);
return returnString;
}
After running the program you will get below output
apple:pistachio:carrot
grape:pistachio:carrot
grape:walnut:tomato
banana:peanut:tomato