How to code this particular method? - java

Lets say I have 3 lists with 3 elements each.List1: "cat, sat, mat"; List2: "every, boy, deserves; List3: all, lines, here . My output should be:
Listout: cat,every,all; cat,every,lines; cat,every,here; cat,boy,all; cat,boy,lines;..
I can write a method that can append all elements of first while there is a loop that runs through the two other lists. But how to tackle this for more than 3 lists. Like 10 lists. The output will contain 3 to the 10 elements. Can you give me an idea of how the code/method in Java would look like? I know I might need recursion: but what would be the input to that recursive method?
I have tried this one like this and it works:
public static LinkedList<String> getPermutations(LinkedList<String> list1, LinkedList<String> list2, LinkedList<String> list3){
LinkedList<String> final_list = new LinkedList<String>();
Iterator<String> it = list1.iterator();
while (it.hasNext()) {
String this_element1 = it.next();
//System.out.println("elem1: "+this_element1);
Iterator<String> it2 = list2.iterator();
while (it2.hasNext()) {
String this_element2 = it2.next();
//System.out.println("elem2: "+this_element2);
Iterator<String> it3 = list3.iterator();
while (it3.hasNext()) {
String this_element3 = it3.next();
//System.out.println(this_element3);
final_list.add(this_element1+","+this_element2+","+this_element3);
}//3
}//2
}//1
return final_list;
}

What you are computing is called the generalized Cartesian Product
This question has a nice Python implementation of how to loop through the Cartesian Product of an arbitrary number of varied-length vectors. Porting it to Java should be fairly easy - though, if you must use LinkedLists, it is better to save Iterators, not indexes, for your counting list.

So far this works: The code is modified from #PhilipWhitehouse and other's comments. Here it is. Please let me know if anyone finds any flaw in this.:
public static LinkedList<String> getPermutationsComb2(LinkedList<LinkedList<String>> lists) {
LinkedList<String> retList = new LinkedList<String>();
if(lists.size() > 1) {
LinkedList<LinkedList<String>> subLists = new LinkedList<LinkedList<String>>();
for(int i = 1; i < lists.size(); i++) {
subLists.add(lists.get(i));
}
LinkedList<String> listTails = getPermutationsComb2(subLists);
Iterator<String> it_tail1 = lists.get(0).iterator();
while(it_tail1.hasNext()){
String listHead2 = it_tail1.next();
Iterator<String> it_tail2 = listTails.iterator();
while(it_tail2.hasNext()){
retList.add(listHead2+","+it_tail2.next());
}
}
} else {
retList = lists.get(0);
}
return retList;
}

For an array of 'n' lists using recursion:
public static LinkedList<String> getPermutations(LinkedList<String>[] lists) {
LinkedList<String> retList = new LinkedList<String>();
Iterator<String> iList = lists[0].iterator();
if (lists.length > 1) {
while (iList.hasNext()) {
String listHead = iList.next();
#SuppressWarnings("unchecked")
LinkedList<String>[] subLists = new LinkedList[lists.length - 1];
for (int i = 1; i < lists.length; i++) {
subLists[i - 1] = lists[i];
}
LinkedList<String> listTails = getPermutations(subLists);
Iterator<String> iTails = listTails.iterator();
while (iTails.hasNext()) {
retList.add(listHead + "," + iTails.next());
}
}
} else {
retList = lists[0];
}
return retList;
}

Related

How can I get the count of most duplicated value in a list after sorting it alphabetically?

What is the easiest way to get the most duplicated value in a list and sorted in descending order...
for example:
List<String> list = new ArrayList<>(List.of("Renault","BMW","Renault","Renault","Toyota","Rexon","BMW","Opel","Rexon","Rexon"));
`
"renault" & "rexon" are most duplicated and if sorted in descending order alphabetically I would like to get the rexon.
I think one of the most readable and elegant way would be to use the Streams API
strings.stream()
.collect(Collectors.groupingBy(x -> x, Collectors.counting()))
.entrySet().stream()
.max(Comparator.comparingLong((ToLongFunction<Map.Entry<String, Long>>) Map.Entry::getValue).thenComparing(Map.Entry::getKey))
.map(Map.Entry::getKey)
.ifPresent(System.out::println);
Create a map of names with their corresponding number of occurrences.
Get names and sort them in descending order.
Print the first name that has the highest number of occurrences.
class Scratch {
public static void main(String[] args) {
List<String> list = List.of("Renault","BMW","Renault","Renault","Toyota","Rexon","BMW","Opel","Rexon","Rexon");
Map<String, Integer> duplicates = new HashMap<>();
// 1. Create a map of names with their corresponding
// number of occurrences.
for (String s: list) {
duplicates.merge(s, 1, Integer::sum);
}
// 2. Get names and sort them in descending order.
List<String> newList = new ArrayList<String>(duplicates.keySet());
newList.sort(Collections.reverseOrder());
// 3. Print the first name that has the highest number of
// occurrences.
Integer max = Collections.max(duplicates.values());
newList.stream().filter(name -> duplicates.get(name).equals(max))
.findFirst()
.ifPresent(System.out::println);
}
}
After some time this is what I came with (I only tested it with your example and it worked):
public class Duplicated {
public static String MostDuplicated(String[] a) {
int dup = 0;
int position = -1;
int maxDup = 0;
for(int i = 0; i < a.length; i++) { //for every position
for(int j = 0; j < a.length; j++){ //compare it to all
if(a[i].equals(a[j])) { dup++; } // and count how many time is duplicated
}
if (dup > maxDup) { maxDup = dup; position = i;}
//if the number of duplications
//is greater than the maximum you have got so far, save this position.
else if (dup == maxDup) {
if( a[i].compareTo(a[position]) > 0 ){ position = i; }
//if its the same, keep the position of the alphabetical last
// (if u want the alphabetical first, just change the "<" to ">")
}
}
return a[position]; //return the position you saved
}
}
You are asking to sort the list and then find the most common item.
I would suggest that the easiest way to sort the list is using the sort method that is built into list.
I would then suggest finding the most common by looping with the for..each construct, keeping track of the current and longest streaks.
I like Yassin Hajaj's answer with streams but I find this way easier to write and easier to read. Your mileage may vary, as this is subjective. :)
import java.util.*;
public class SortingAndMostCommonDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>(List.of("Renault","BMW","Renault","Renault","Toyota","Rexon","BMW","Opel","Rexon","Rexon"));
list.sort(Comparator.reverseOrder());
System.out.println(list);
System.out.println("The most common is " + mostCommon(list) + ".");
}
private static String mostCommon(List<String> list) {
String mostCommon = null;
int longestStreak = 0;
String previous = null;
int currentStreak = 0;
for (String s : list) {
currentStreak = 1 + (s.equals(previous) ? currentStreak : 0);
if (currentStreak > longestStreak) {
mostCommon = s;
longestStreak = currentStreak;
}
previous = s;
}
return mostCommon;
}
}
The fast algorithm takes advantage of the fact that the list is sorted and finds the list with the most duplicates in O(n), with n being the size of the list. Since the list is sorted the duplicates will be together in consecutive positions:
private static String getMostDuplicates(List<String> list) {
if(!list.isEmpty()) {
list.sort(Comparator.reverseOrder());
String prev = list.get(0);
String found_max = prev;
int max_dup = 1;
int curr_max_dup = 0;
for (String s : list) {
if (!s.equals(prev)) {
if (curr_max_dup > max_dup) {
max_dup = curr_max_dup;
found_max = prev;
}
curr_max_dup = 0;
}
curr_max_dup++;
prev = s;
}
return found_max;
}
return "";
}
Explanation:
We iterate through the list and keep track of the maximum of duplicates found so far and the previous element. If the current element is the same as the previous one we increment the number of duplicates found so far. Otherwise, we check if the number of duplicates is the bigger than the previous maximum of duplicates found. If it is we update accordingly
A complete running example:
public class Duplicates {
private static String getMostDuplicates(List<String> list) {
if(!list.isEmpty()) {
list.sort(Comparator.reverseOrder());
String prev = list.get(0);
String found_max = prev;
int max_dup = 1;
int curr_max_dup = 0;
for (String s : list) {
if (!s.equals(prev)) {
if (curr_max_dup > max_dup) {
max_dup = curr_max_dup;
found_max = prev;
}
curr_max_dup = 0;
}
curr_max_dup++;
prev = s;
}
return found_max;
}
return "";
}
public static void main(String[] args) {
List<String> list = new ArrayList<>(List.of("Renault","BMW","Renault","Renault","Toyota","Rexon","BMW","Opel","Rexon","Rexon"));
String duplicates = getMostDuplicates(list);
System.out.println("----- Test 1 -----");
System.out.println(duplicates);
list = new ArrayList<>(List.of("Renault","BMW"));
duplicates = getMostDuplicates(list);
System.out.println("----- Test 2 -----");
System.out.println(duplicates);
list = new ArrayList<>(List.of("Renault"));
duplicates = getMostDuplicates(list);
System.out.println("----- Test 3 -----");
System.out.println(duplicates);
}
}
Output:
----- Test 1 -----
Rexon
----- Test 2 -----
Renault
----- Test 3 -----
Renault
Actually, I found a solution which works:
public static void main(String[] args) {
List<String> list = new ArrayList<>(List.of("Renault", "BMW", "BMW", "Renault", "Renault", "Toyota",
"Rexon", "BMW", "Opel", "Rexon", "Rexon"));
Map<String, Integer> soldProducts = new HashMap<>();
for (String s : list) {
soldProducts.put(s, soldProducts.getOrDefault(s, 0) + 1);
}
LinkedHashMap<String, Integer> sortedMap = soldProducts.entrySet()
.stream()
.sorted(VALUE_COMPARATOR.thenComparing(KEY_COMPARATOR_REVERSED))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2, LinkedHashMap::new));
String result = "";
for (Map.Entry<String, Integer> s : sortedMap.entrySet()) {
result = s.getKey();
}
System.out.println(result);
}
static final Comparator<Map.Entry<String, Integer>> KEY_COMPARATOR_REVERSED =
Map.Entry.comparingByKey(Comparator.naturalOrder());
static final Comparator<Map.Entry<String, Integer>> VALUE_COMPARATOR =
Map.Entry.comparingByValue();

Grouping the nested loop elements based on the first iteration variable in Java

I have 2 lists one for the sentence one for the keywords. The idea is to check if the sentence have the keywords. and put them in a list for each sentence in order.
I am sorry if this is already duplicated here in advance.
List <String> sentence= new ArrayList <>();
sentence.add("this is a good dog");
sentence.add("cats drink milk");
sentence.add("Animals are beautiful creatures");
List <String> keyword= new ArrayList <>();
keyword.add("dog");
keyword.add("cats");
keyword.add("beautiful");
keyword.add("good");
keyword.add("are");
keyword.add("this");
keyword.add("milk");
My idea was to create 2 nested loops for each list:
for (int b = 0; b < sentence.size(); b++) {
for (int c = 0; c < keyword.size(); c++) {
if (sentence.get(b).contains(keyword.get(c))) {
System.out.println(keyword.get(c));
}
}
}
The output of this is:
dog
good
this
cats
milk
beautiful
are
The desired output would be:
[this,good,dog]
[cats,milk]
[are,beautiful]
So it is like getting all the existing keywords, in the order of the sentence,not related to keywords order.
and then group the existing keywords for each sentence, as in the order of existence.
Hope it is clear. Would really appreciate any ideas. doesnt have to follow the same method.
Iterate over your sentence list. For each sentence iterate over your keyword list. Add each found keyword found in a tempList, sort the tempList by the index of keyword in sentence and finally add each tempList to a list of lists. Example:
public static void main(String[] args) {
List <String> sentence= new ArrayList <>();
sentence.add("this is a good dog");
sentence.add("cats drink milk");
sentence.add("Animals are beautiful creatures");
List <String> keyword= new ArrayList <>();
keyword.add("dog");
keyword.add("cats");
keyword.add("beautiful");
keyword.add("good");
keyword.add("are");
keyword.add("this");
keyword.add("milk");
List<List<String>> result = new LinkedList<>();
for(String sen: sentence){
List<String> tempList = new ArrayList<>();
for(String key: keyword){
if(sen.contains(key)){
tempList.add(key);
}
}
tempList.sort(new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return sen.indexOf(o1) - sen.indexOf(o2) ;
}
});
result.add(tempList);
}
for(List<String> r : result){
System.out.println(r);
}
}
You need a slight modification in your looping
for (int i = 0; i < sentence.size(); i++) {
String[] matchArray = new String[sentence.get(i).split(" ").length];
for (int j = 0; j < keyword.size(); j++) {
if (sentence.get(i).contains(keyword.get(j))) {
matchArray[Arrays.asList(sentence.get(i).split(" ")).indexOf(keyword.get(j))] = keyword.get(j);
}
}
List<String> matchList = new ArrayList<String>();
for(String match: matchArray) {
if(match != null) {
matchList.add(match);
}
}
System.out.println(matchList);
}
For every sentence create an array with size same as the sentence (just to ensure size). Now when matches are found get the index of the match from sentence and add element to that particular index of the array. So at the end of keyword iteration you will have all matches in array with null values if some words are not matching.
Now declare a new List of String into which add the elements from array which are not null. At last print the list.
I think Map would be a good choice here. Just make sentences keys for the map and keywords as value. Following is the code for the same.
Map <String, ArrayList<String>> sentences= new HashMap<>();
sentences.put("this is a good dog", new ArrayList<>());
sentences.put("cats drink milk", new ArrayList<>());
sentences.put("Animals are beautiful creatures", new ArrayList<>());
List <String> keyword= new ArrayList <>();
keyword.add("dog");
keyword.add("cats");
keyword.add("beautiful");
keyword.add("good");
keyword.add("are");
keyword.add("this");
keyword.add("milk");
keyword.forEach(word -> sentences.entrySet().stream()
.filter(map -> map.getKey().contains(word)).
forEach(map -> sentences.computeIfAbsent(map.getKey(), key->new ArrayList<>()).add(word)));
sentences.forEach((key, value) -> System.out.println(value));
Try something like this:
for (String sen: sentence) {
System.out.print("[");
boolean first = true;
for (String word: sen.split("[\\s\\p{Punct}]")) {
if (keyword.contains(word)) {
if (first) {
first = false;
} else {
System.out.print(",");
}
System.out.print(word);
}
}
System.out.println("]");
}
this should do it, printing exactly in the format you requested :
for (int b = 0; b < sentence.size(); b++) {
String arr[] = sentence.get(b).split("\\s+");
List result = new ArrayList<>();
for (int c = 0; c < arr.length; c++ ) {
if (keyword.contains(arr[c]))
result.add(arr[c]);
}
System.out.println(result);
}
I would use the following :
for(String currentSentence : sentence) {
List<String> keywordsInSentence = new ArrayList<>();
for (String word : currentSentence.split("\\s+")) {
if (keyword.contains(word)) {
keywordsInSentence.add(word);
}
}
System.out.println(keywordsInSentence);
}
You can try it here.
(and I'd rename sentence into sentences or sentenceList and similarly for keyword, otherwise it's just confusing)
If you need to do anything more to the keywords than immediately displaying them, you could insert the keywordsInSentence lists into a Map<String, List<String>> you would value by replacing the System.out.println by map.put(currentSentence, keywordsInSentence).

Iterating through a List of Arrays and printing every element within the Arrays

I seem to be having trouble in the logic of my problem. What I am trying to do is have a List of Arrays. Each Array contains 2 String.
I am trying to iterate through my List and then printing the elements of the arrays. I seem to get stuck in printing the first Array (which is what my code does), though I am stuck in the logic.
public static void main(String[] args) {
List<List<String>> addresses = new ArrayList<List<String>>();
ArrayList<String> singleAddress1 = new ArrayList<String>();
singleAddress1.add("17 Fake Street");
singleAddress1.add("18 Fake Street");
ArrayList<String> singleAddress2 = new ArrayList<String>();
singleAddress2.add("Phoney town");
singleAddress2.add("not real town");
ArrayList<String> singleAddress3 = new ArrayList<String>();
singleAddress3.add("sillyname town");
singleAddress3.add("alsosilly town");
addresses.add(singleAddress1);
addresses.add(singleAddress2);
addresses.add(singleAddress3);
System.out.print("Original contents of al: " + addresses + "\n");
Iterator itr = addresses.iterator();
while (itr.hasNext()) {
Object element = itr.next();
System.out.print(element + "\n");
for (int i = 0; i < singleAddress1.size(); i++) {
System.out.println(singleAddress1.get(i));
}
itr.remove();
}
}
}
Whilst you are iterating over the outer array list addresses, internally you end up iterating on same singleAddress1 instead of all the list elements which you would get from iterator using for (int i = 0; i < singleAddress1.size(); i++) {.
Your iteration loop should be:
Iterator<List<String>> itr = addresses.iterator();
while (itr.hasNext()) {
List<String> element = itr.next();
^^^^^^^^^^^^
System.out.print(element + "\n");
for (int i = 0; i < element.size(); i++) {
^^^^^^^^
System.out.println(element.get(i));
}
itr.remove();
}
Why don't you use a simple for-each loop:
for(List<String> list:addresses)
{
for(String str:list)
{
System.out.println(str);
}
}

Using ListIterator to remove duplicates

/** Return a list of all items in L that appear more than once.
* Each item appears once in the result.
*/
static List<String> duplicates(List<String> L) {
ArrayList<String> result = new ArrayList<String>();
int n;
n = 0;
for (ListIterator<String> p1 = L.listIterator(); p1.hasNext();
n += 1) {
String x = p1.next();
if (result.contains(x)) {
continue;
}
int m;
m = L.size() - 1;
for (ListIterator<String> p2 = L.listIterator(L.size());
m > n; m -= 1) {
if (x.equals(p2.previous())) {
result.add(x);
break;
}
}
}
Collections.sort(result);
return result;
}
I am trying to revise this code so that I don't use any other variables other than result, p1, and p2. This is what I have for now, but I am pretty lost on how to work this out.
ListIterator<String> p1 = L.listIterator();
while (p1.hasNext()) {
String x = p1.next();
if result.contains(x)) {
continue;
}
Since you have to remove duplicates, is there any reason you using ArrayList?
This can solve your issue in one line;
Set<String> result = new TreeSet<String>(p1);
Also, to simplify your code, would recommend to use for-each loop rather than the iterator.
for(String s : p1)
{ // do some operation with the String you got here. }
This could suit your needs too:
List<String> noDuplicates = new ArrayList<String>(new TreeSet<String>(initialList));
This is very complex. You would do yourself a favour by using the for(String s: List<String>) construct. You may also want to use a Set to help you find duplicates. Here's what a solution might look like.
Set<String> items = new HashSet<>();
Set<String> dupes = new TreeSet<>();
for(String s: L) {
if (!items.add(s)) {
// collect your duplicate here
dupes.add(s);
}
}

Dynamically create loops to iterate over a List of List<String>'s

I have a List of List<String>'s which I get from a external API method call:
List<List<String>> outerList
I have to create unique key combinations by concatenating strings from each list in the same order they are in the outer list.
Example: If outer list has 2 inner lists, say list1: {"A","B"} and list2: {"C","D"}. Then possible unique combinations will be AC, AD, BC and BD.
But the problem is the outerList size is dynamic, it can contain any number of inner lists. If the inner list numbers are fixed then I can write for loops and create combinations.
I am thinking in the direction of using reflections, recursion etc but so far have not been able to solve it.
public static void main(String[] args) {
List<List<String>> outerList = new ArrayList<List<String>>();
List<String> list1 = new ArrayList<String>();
list1.add("A");
list1.add("B");
List<String> list2 = new ArrayList<String>();
list2.add("C");
list2.add("D");
outerList.add(list1);
outerList.add(list2);
for(String s1: list1) {
for(String s2: list2) {
System.out.println(s1+s2);
}
}
}
Here outerList has 2 inner lists so I have created 2 for loops explicitly to iterate and concatenate. But in real-time outerList can have any number of inner lists, how to loop dynamically loop through all the inner loops and concatenate?
This code works for me:
public class Test
{
public static void generate(LinkedList<LinkedList<String>> outerList, String outPut) {
LinkedList<String> list = outerList.get(0);
for(String str : list) {
LinkedList<LinkedList<String>> newOuter = new LinkedList<LinkedList<String>>(outerList);
newOuter.remove(list);
if(outerList.size() > 1) {
generate(newOuter, outPut+str);
} else {
System.out.println(outPut+str);
}
}
}
public static void main(String[] args)
{
LinkedList<LinkedList<String>> outerList = new LinkedList<LinkedList<String>>();
LinkedList<String> list1 = new LinkedList<String>();
LinkedList<String> list2 = new LinkedList<String>();
list1.add("A");
list1.add("B");
list2.add("C");
list2.add("D");
outerList.add(list1);
outerList.add(list2);
Test.generate(outerList, "");
}
}
Output:
AC
AD
BC
BD
Sample data with enough variation to demonstrate the problem:
List<List<String>> outerList = new ArrayList<List<String>>();
List<String> innerList1 = new ArrayList<String>();
innerList1.add("A");
innerList1.add("B");
outerList.add(innerList1);
List<String> innerList2 = new ArrayList<String>();
innerList2.add("X");
innerList2.add("Y");
innerList2.add("Z");
outerList.add(innerList2);
List<String> innerList3 = new ArrayList<String>();
innerList3.add("P");
innerList3.add("Q");
innerList3.add("R");
outerList.add(innerList3);
Keep an array of counters:
int[] positions = new int[outerList.size()];
boolean another = true;
while (another) {
for (int n = 0; n < outerList.size(); n++) {
System.out.print(outerList.get(n).get(positions[n]));
}
System.out.println();
another = false;
for (int c = 0; c < outerList.size(); c++) {
positions[c]++;
if (positions[c] < outerList.get(c).size()) {
another = true;
break;
}
positions[c] = 0;
}
}
Each time around the main loop, I print one item from each inner list. Then I advance the counters, starting with the first. If that doesn't go off the end of the first inner list, we're ready to print again. But if it does, I set that counter to zero and try advancing the second one, and so on. If they all wrap round to zero, it's time to quit.
It's really just like counting except that the columns each have a different "base" (instead of all being base ten or two or whatever).

Categories