Grouping two arrays into one array of common results - java

This is a logic problem I cant seem to wrap my head around.
What I wish to achieve is to match two different products from two different sets that have the same total value into packages.
for simplicity sake lets say we have two arrays with [id,price] pairs
array1 = [id=A,price=1],[id=B,price=2],[id=C,price=3]
array2 = [id=A,price=2],[id=B,price=1],[id=C,price=1]
the cheapest package I can make is for $2 by combining array1 [id A] and array2 [id B]
but I can also combine array1 [id A] and array2 [id C] to make a $2 package.
So what I am trying to get is a set of packages that could be grouped by total value. but only according to what the is selected in the first array.
eg : (purely for visualization purposes) :
package1 :
total : $2
1st option :
[id=A,price=1]
2nd option
[id=B,price=1]
[id=C,price=1]
package2 :
total : $3
1st option :
[id=A,price=1]
2nd option
[id=A,price=2]
package3 :
total : $3
1st option :
[id=B,price=2]
2nd option
[id=B,price=1]
[id=C,price=1]
etc.
Im assuming I will need to recursively iterate through the results, I just keep going down the wrong path and maybe someone could point me in the right direction.

Best option is to calculate result for all combinations, and store the options to a map structure at the time the results are calculated.
If you are using a custom object for your class (MyOption):
Map<Integer, Map<MyOption, List<MyOption>> result = new HashMap<>();
Or, if you're using object array:
Map<Integer, Map<Object[], List<Object[]>> result = new HashMap<>();

Maybe you can generate a [price] <--> [item list] map, the key is price, the value is a list of item with same price. e.g.
[1] -- [Item A, Item B], [2] -- [Item D, Item E, Item Z], then you can generated different package base on the map.
private void methodToGenerateCombinationOfItems {
Map<Integer, List<Item>> map = new HashMap<Integer, List<Item>>();
updateArrayDataToMap(map, array1);
updateArrayDataToMap(map, array2);
... ...
// now the map should contains [price X] <--> [list of items with price X]
// if you want to order by price, you may want to use TreeMap instead of HashMap.
}
private void updateArrayDataToMap(Map<Integer, List<Item>> map, List<Item> itemArr) {
for( Item item : itemArr) {
if( map.contains(item.getPrice()) ) {
map.get(item.getPrice()).add(item);
} else {
List<Item> listTmp = new ArrayList<Item>();
listTmp.add(item);
map.put(item.getPrice(), listTmp);
}
}
}

The pseudo code for this:
List<Package> results = new ArrayList<>();
for(Item item:array1) {
if (item.getPrice() < 2) {
addAllPackagesStartingWith(item, results);
}
}
// add all packages where an item from array 1 can be paired with an item in array 2
void addAllPackagesStartingWith(Item item, List<Package> results) {
for (Item array2Item:array2) {
if(item.getPrice() + array2Item.getPrice() < 2) {
results.add(new Package(item, array2Item));
}
}
}

Related

Java stream with list

I'm new to streams and how they work and I am trying to get the occurrences of a specific object that is added in the list.
I found a way doing this using Collections. It goes as follows:
for (int i = 0; i < countries.size(); i++) {
int occurrences = Collections.frequency(countries, countries.get(i));
}
But I want to use stream.
The method I used with streams was:
countries.parallelStream().filter(p -> p.contentEquals(countries.get(countries.size()-1))).count()
This only returns the current object and its occurrences, instead I want all the objects and their occurrences.
Edit:
`private final ArrayList<String> countries = new ArrayList<>();
dataset.setValue(countries.parallelStream()
.filter(p -> p.contentEquals(countries.get(countries.size()-1)) )
.count(),
"",
countries.get(countries.size()-1)); //sets the graph for the given country
#Override
public void addCountries(String country) {
countries.add(country);
}
#Override
public void removeCountries(int country) {
countries.remove(country);
}`
I am making a graph. The first statement of dataset.setValue() is the amount of occurrences of the country. This has to be done for each country so you can see how many occurrences of a country there is. hope this helps
the graph
Edit 2: solved!
countries.stream().distinct().forEach(o ->
dataset.setValue(Collections.frequency(countries, o),
"",
o)); //sets the graph for the given country
You could also use grouping collector:
Collection<Integer> collection = Arrays.asList(1, 2, 1, 4, 2);
final Map<Integer, Long> map = collection.stream().collect(
Collectors.groupingBy(el -> el, Collectors.counting()));
System.out.println(map);
This produces
{1=2, 2=2, 4=1}
You can do this:
List<Integer> lista = new ArrayList<>(Arrays.asList(1,2,3,3,2,1,5,4,1,2,3));
lista.stream().distinct().forEach(o -> System.out.println(o + " occures " + Collections.frequency(lista, o) + " times in a list !"));
Output:
1 occures 3 times in a list !
2 occures 3 times in a list !
3 occures 3 times in a list !
5 occures 1 times in a list !
4 occures 1 times in a list !
In short:
We make stream out of your list, we remove duplicates from the stream by using .distinct(), and now when we are left with unique elements from the list we use Collections.frequency to print out how many times each element occurs in the list.

How to add element of a List of List and generate a new List

I have some data which is stored in List<List<String>> so to get the data I am using this method
private static void finalResult(List<List<String>> resultList) {
for (List<String> listOFResults : resultList) {
if(listOFResults.get(0).equals("v1")){
System.out.println("Vehicle is :: "+listOFResults);
}
}
}
my output is like this
Vehicle is :: [v1, route1, 1.4, destination1]
Vehicle is :: [v1, route2, 2.3, destination1]
Vehicle is :: [v1, route3, 1.2, destination2]
Vehicle is :: [v1, route4, 3.4, destination2]
my query is to add index value 2 i.e 1.4,2.3,1.2,3.4 but the addition has to be in
`route1 + route4` = 1.4 + 3.4
and after addition I want to store the values of both list in a common List
like
value is :: [v1,route1,destination1,route4,destination2,4.8];
value is :: [v1,route2,destination1,route4,destination2,5.7];
value is :: [v1,route3,destination2,route4,destination1,4.6];
here I have 3 possible ways to reach my destination here I am filtering for my vehicle 1. Now what I have in my output is my route deatils and time taken to travel. I want to add the 2 routes to compare which can be faster to cover both destination. So possible ways can be Route1 +Route4,Route2+Route4 and Route3+Route4
how to achieve this.
Depending if my assumptions on your question are right, here is a possible solution:
public static void main(String[] args) {
List<String> a1 = Arrays.asList("v1", "route1", "1.4", "destination1");
List<String> a2 = Arrays.asList("v1", "route2", "2.3", "destination1");
List<String> a3 = Arrays.asList("v2", "route2", "3.0", "destinationx");
List<String> a4 = Arrays.asList("v1", "route3", "1.2", "destination2");
List<String> a5 = Arrays.asList("v1", "route4", "3.4", "destination2");
List<List<String>> all = List.of(a1, a2, a3, a4, a5);
List<String> str = all.stream().filter(l -> "v1".equals(l.get(0)))
.map(l -> {
double v = Double.parseDouble(l.get(2)) + Double.parseDouble(a5.get(2));
return String.format("%s,%s,%s,%s,%s,%1.1f", l.get(0), l.get(1), l.get(3), "route4", a5.get(3), v);
})
.collect(Collectors.toList());
str.forEach(System.out::println);
}
This prints out the following:
v1,route1,destination1,route4,destination2,4.8
v1,route2,destination1,route4,destination2,5.7
v1,route3,destination2,route4,destination2,4.6
v1,route4,destination2,route4,destination2,6.8
What this code does?
it filters the "v1" elements
performs the calculation and creates the string in the format you specified
collects these strings into a list
But honestly: the best thing would be to create proper Plain Old Java Objects (POJO) with the fields corresponding to your data model. Shuffling strings around like what I did is never the best idea.

Count and remove similar elements in a list while iterating through it

I used many references in the site to build up my program but I'm kind of stuck right now. I think using iterator will do the job. Sadly even though I went through questions which had iterator, I couldn't get the way of using it properly to implement it on my code.
I want to,
1. remove the similar elements found in the list fname
2. count & add the that count of each element found in fname to
counter.
Please help me do the above using iterator or with any other method. Following is my code,
List<String> fname = new ArrayList<>(Arrays.asList(fullname.split(""))); //Assigning the string to a list//
int count = 1;
ArrayList<Integer> counter = new ArrayList<>();
List<String> holder = new ArrayList<>();
for(int element=0; element<=fname.size; element++)
{
for(int run=(element+1); run<=fname.size; run++)
{
if((fname.get(element)).equals(fname.get(run)))
{
count++;
holder.add(fname.get(run));
}
counter.add(count);
}
holder.add(fname.get(element));
fname.removeAll(holder);
}
System.out.println(fname);
System.out.println(counter);
Thanks.
From your questions, you basically want to:
1. Eliminate duplicates from given String List
You can simply convert your List to HashSet (it doesn't allow duplicates) and then convert it back to list (if you want the end result to be a List so you can do something else with it...)
2. Count all occurences of unique words in your list
The fastest coding is to use Java 8 Streams (code borrowed frome here: How to count the number of occurrences of an element in a List)
Complete code
public static void main(String[] args) {
String fullname = "a b c d a b c"; //something
List<String> fname = new ArrayList<>(Arrays.asList(fullname.split(" ")));
// Convert input to Set, and then back to List (your program output)
Set<String> uniqueNames = new HashSet<>(fname);
List<String> uniqueNamesInList = new ArrayList<>(uniqueNames);
System.out.println(uniqueNamesInList);
// Collects (reduces) your list
Map<String, Long> counts = fname.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
System.out.println(counts);
}
I do not think that you need iterators here. However, there are many other possible solutions you could use, like recursion. Nevertheless, I have just modified your code as the following:
final List<String> fname = new ArrayList<String>(Arrays.asList(fullname.split("")));
// defining a list that will hold the unique elements.
final List<String> resultList = new ArrayList<>();
// defining a list that will hold the number of replication for every item in the fname list; the order here is same to the order in resultList
final ArrayList<Integer> counter = new ArrayList<>();
for (int element = 0; element < fname.size(); element++) {
int count = 1;
for (int run = (element + 1); run < fname.size(); run++) {
if ((fname.get(element)).equals(fname.get(run))) {
count++;
// we remove the element that has been already counted and return the index one step back to start counting over.
fname.remove(run--);
}
}
// we add the element to the resulted list and counter of that element
counter.add(count);
resultList.add(fname.get(element));
}
// here we print out both lists.
System.out.println(resultList);
System.out.println(counter);
Assuming String fullname = "StringOfSomeStaff"; the output will be as the following:
[S, t, r, i, n, g, O, f, o, m, e, a]
[3, 2, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1]
You can try something like this:
Set<String> mySet = new HashSet<>();
mySet.addAll( fname ); // Now you have unique values
for(String s : mySet) {
count = 0;
for(String x : fname) {
if( s.equals(x) ) { count++; }
}
counter.add( count );
}
This way we don't have a specific order. But I hope it helps.
In Java 8, there's a one-liner:
List<Integer> result = fname
.stream()
.collect(Collectors.groupingBy(s -> s))
.entrySet()
.stream()
.map(e -> e.getValue().size())
.collect(Collectors.toList());
I was using LinkedHashMap to preserve order of elements. Also for loop, which I am using, implicitly uses Iterator. Code example is using Map.merge method, which is available since Java 8.
List<String> fname = new ArrayList<>(Arrays.asList(fullname.split("")));
/*
Create Map which will contain pairs kay=values
(in this case key is a name and value is the counter).
Here we are using LinkedHashMap (instead of common HashMap)
to preserve order in which name occurs first time in the list.
*/
Map<String, Integer> countByName = new LinkedHashMap<>();
for (String name : fname) {
/*
'merge' method put the key into the map (first parameter 'name').
Second parameter is a value which we that to associate with the key
Last (3rd) parameter is a function which will merge two values
(new and ald) if map already contains this key
*/
countByName.merge(name, 1, Integer::sum);
}
System.out.println(fname); // original list [a, d, e, a, a, f, t, d]
System.out.println(countByName.values()); // counts [3, 2, 1, 1, 1]
System.out.println(countByName.keySet()); // unique names [a, d, e, f, t]
Also same might be done using Stream API but it would be probably hard for understanding if you are not familiar with Streams.
Map<String, Long> countByName = fname.stream()
.collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()));

Java: display values based on sorted keys in hashmap

I have a HashMap, i have sorted the categories and put it in a list ie initially the categories were : - A,B,C,D and after sorting it is D,C,B,A and i've added it to the List.
I want to display questions based on the sorted order of category i.e
Display all questions with category :- D
then Display all questions with category :- C and so on.
here is what I've tried:-
List<Category> list = Arrays.asList(Category.values());
List<Question> list1 = new ArrayList<>();
list1.addAll(questionList);
Collections.sort(list, new Comparator<Category>() {
#Override
public int compare(Category o1, Category o2) {
return o2.ordinal() - o1.ordinal();
}
});
System.out.println("Categories" +list);
Map< List<Category>,List<Question>> map = new HashMap<>();
map.put(list, list1);}}
boolean ty = list1.containsAll(list1);
if(ty==true){
out.println(list1.get(0).getQuestion()) ;}
i want my output to be like this:-
D: what is your name?
how are you?
C: another question1?
another question2?
B: another question3?
another question4?
I want to display questions based on the sorted order of category i.e
Display all questions with category :- D then Display all questions
with category :- C and so on.
To perform your need, questions must be related to a category.
You have two ways of doing :
using a comparator (as #Surace done) to sort all questions in a final list.
creating a map (list of questions as value and category as key)
Comparator is more concise and it is rather a good idea but in your case it has a drawback, it doesn't keep the category associated to each question while you want it in your rendering :
i want my output to be like this:-
D: what is your name? how are you?
C: another question1? another question2?
B: another question3? another question4?
You may retrieve the information with category information stored in the question but it forces you to do rather clumsy processing during iteration because the category is not a external information but a computed information that you have to search in another object.
By creating a map which associates questions by category, you just need to iterate to render the information and in more general way you may perform any additional processing for each iteration of category.
Here the code :
public static void main(String[] args) {
// create your questions
List<Question> questionsInput = new ArrayList<>();
questionsInput.add(new Question("question 1 For A?", Category.A));
questionsInput.add(new Question("question 2 For A?", Category.A));
questionsInput.add(new Question("question 1 For A?", Category.B));
questionsInput.add(new Question("question 2 For A?", Category.B));
Map<Category, List<Question>> map = associateQuestionByCat(questionsInput);
// display info
for (Entry<Category, List<Question>> entry : map.entrySet()) {
System.out.print("cat " + entry.getKey() + ":");
for (Question q : entry.getValue()) {
System.out.print(q.getQuestion());
}
System.out.println("");
}
}
public static Map<Category, List<Question>> associateQuestionByCat(List<Question> questions ) {
Map<Category, List<Question>> questionsByCategory = new TreeMap<>(Collections.reverseOrder());
for (Question q : questions) {
final Category currentCat = q.getCat();
List<Question> questionsForCurrentCat = questionsByCategory.get(currentCat);
if (questionsForCurrentCat == null) {
questionsForCurrentCat = new ArrayList<>();
questionsByCategory.put(currentCat, questionsForCurrentCat);
}
questionsForCurrentCat.add(q);
}
return questionsByCategory;
}
}
I think this will give your expected output.
Collections.sort(list, new Comparator<Category>() {
#Override
public int compare(Category o1, Category o2) {
// o1.getCategoryName() is A or B or C or D
return o1.getCategoryName().compareTo(o2.getCategoryName());
}
});

Re-order ArrayList Based on String Array's Order - Java

I have one arraylist and one String array. The String array contains IDs and the Array List contains the ids and information related to those Ids. This ArrayList is in an undesirable order. I have a String Array of the Ids in the order in which I want them to be in the ArrayList.
Semi-Pseudocode Example:
ArrayList<MyObject> myList = new ArrayList<MyObject>();
for (every username)
{
myList.add(new MyObject(id, username, content, country);
}
String[] ids = new String[myList.size()];
...Ids are added and sorted here...
I now have a list of Ids, in their correct order. Each Id in "myList" corresponds to an Id in the "ids" String Array. I want to sort "myList" based on the order of it's corresponding id in the "ids" String Array.
How can I re-sort my ArrayList in such a way?
Eg. if in Array list I have:
1. 123, Bob, test, USA
2. 1234, Vladimir, test, USA
3. 12345, Yoseph, test, USA
and in the String[] I have:
1. 1234
2. 123
3.12345
How can I reorder the ArrayList based off of the Ids in the String Array, thus producing:
1. 1234, Vladimir, test, USA
2. 123, Bob, test, USA
3. 12345, Yoseph, test, USA
One solution would be to iterate over the ids array, and search the object for the current id in the array. We know its final (desired) position: it is the index in the array (because we want the list sorted just like the array), so we can move this element to its final place in the list (we do this by swapping it with the element being at the position we're at currently in the array).
for (int i = ids.length - 1; i > 0; i--) { // Downward for efficiency
final String id = ids[i];
// Big optimization: we don't have to search the full list as the part
// before i is already sorted and object for id can only be on the remaining
for (int j = i; j >= 0; j--) // NOTE: loop starting at i
if (id.equals(myList.get(j).getId()) {
Collections.swap(myList, j, i);
break;
}
}
Note: the for loop omits the last element (i==0) because if all other elements are in place, the last is also in (its) place.
This is much faster than creating a comparator and using a sorting algorithm (which Collections.sort() does for example) because the order of the elements is already known (defined by the ids array) and sorting algorithms (no matter how smart the algorithms are) can only use the info [less | equals | greater] returned by comparators.
You could write your own Comparator based on the index in the array:
public class MyObjectComparator implements Comparator<MyObject> {
private List<String> ids;
public MyObjectComparator(String[] ids) {
this.ids = Arrays.asList(ids); // Copying the array would be safer
}
public int compare (MyObject obj1, MyObject obj2) {
return Integer.compare(ids.indexOf(obj1), ids.indexOf(obj2));
}
}
// Use it:
Collections.sort (myList, new MyObjectComparator(ids));
You simply need a comparator:
List<String> ids = Arrays.asList(array);
Collections.sort(list, new Comparator<MyObject>() {
#Override
public int compare(MyObject o1, MyObject o2) {
return Integer.compare(ids.indexOf(o1.getId()), ids.indexOf(o2.getId()));
}
});
Of course, if your list is large, this will be very inefficient. So you'd better build a Map<String, Integer> containing each ID as key and its position in the array as value, and use this map inside the comparator:
Map<String, Integer> idPositions = new HashMap<>();
for (int i = 0; i < array.length; i++) {
idPositions.put(array[i], i);
}
Collections.sort(list, new Comparator<MyObject>() {
#Override
public int compare(MyObject o1, MyObject o2) {
return idPositions.get(o1.getId()).compareTo(idPositions.get(o2.getId()));
}
});
crs_rawStepSeqNum: Your arrayList
crs_rawStepSeqNum: Same arrayList
for(int x =0;x<crs_rawStepSeqNum.size();x++)
if((x+1) < crs_rawStepSeqNum.size()) {
if (Integer.parseInt(crs_rawStepSeqNum.get(x)) > Integer.parseInt(crs_rawStepSeqNum.get(x + 1))) {
crs_rawStepSeqNum.set(x, crs_rawStepSeqNum.get(x + 1));
crs_rawStepSeqNum.set(x + 1, crs_StepSeqNum.get(x));
crs_StepSeqNum.clear();
crs_StepSeqNum.addAll(crs_rawStepSeqNum);
x=0;
}
}
}

Categories

Resources