This question already has answers here:
Merge two arrays and remove duplicates in Java
(7 answers)
Closed 1 year ago.
I was able to get the two arrays to sort and merge but I can not figure out how to remove the duplicates. Can someone please help me with this? Here is my code so far:
public class FinalArray {
public static void main(String[] args) {
String[] testArray1 = {"coffee", "tea", "water"};
String[] testArray2 = {"lemonade", "juice", "water"};
mergeUniqueValues(testArray1, testArray2);
}
public static void mergeUniqueValues(String[] arr1, String[] arr2) {
String[] arr3 = new String[arr1.length + arr2.length];
for (int i = 0; i < arr1.length; i++) {
arr3[i] = arr1[i];
}
for (int i = arr1.length, index = 0; i < arr1.length + arr2.length; i++, index++) {
arr3[i] = arr2[index];
}
Arrays.sort(arr3);
System.out.println("Your sorted array is: ");
for (String str : arr3) {
System.out.println(str);
}
}
}
Property of Set: It does not allow duplicates.
You can simply convert the array to Set (to avoid duplicates) and then convert it back to an array.
Here is a sample code for your reference:
public class Main {
public static void main(String[] args) {
String[] testArray1 = {"coffee", "tea", "water"};
String[] testArray2 = {"lemonade", "juice", "water"};
mergeUniqueValues(testArray1, testArray2);
}
public static void mergeUniqueValues(String[] arr1, String[] arr2) {
Set noDuplicateSet = new HashSet();
noDuplicateSet.addAll(Arrays.asList(arr1));
noDuplicateSet.addAll(Arrays.asList(arr2));
String[] noDuplicateArray = new String[noDuplicateSet.size()];
noDuplicateSet.toArray(noDuplicateArray);
Arrays.sort(noDuplicateArray);
System.out.println("Your sorted array is: ");
for (String str : noDuplicateArray) {
System.out.println(str);
}
}
}
Output:
Your sorted array is:
coffee
juice
lemonade
tea
water
You can use Java Streams and distinct().
String[] result =
Stream.concat( // combine
Stream.of(array1),
Stream.of(array1))
.distinct() // filter duplicates
.sorted() // sort
.toArray(String[]::new);
You can take advantage from the java.util.TreeSet class, which is a collection which implements java.util.Set, and made of all unique values ordered by the natural order of the given elements. In your case, String does implement Comparable, so it can be naturally ordered when the element are inserted in the collection.
Here is the code you can test:
import java.util.*;
public class MergeArray {
public static void main(String[] args) {
String[] testArray1 = { "coffee", "tea", "water" };
String[] testArray2 = { "lemonade", "juice", "water" };
mergeUniqueValues(testArray1, testArray2);
}
public static void mergeUniqueValues(String[] arr1, String[] arr2) {
Set<String> mergedList = new TreeSet(Arrays.asList(arr1));
mergedList.addAll(Arrays.asList(arr2));
String[] arr3 = mergedList.toArray(String[]::new);
System.out.println("Your sorted array is: ");
for (String str : arr3) {
System.out.println(str);
}
}
}
And here is the output:
Your sorted array is:
coffee
juice
lemonade
tea
water
You can use Java Stream:
String[] testArray1 = {"coffee", "tea", "water"};
String[] testArray2 = {"lemonade", "juice", "water"};
String[] testArray3 = Stream.of(testArray1, testArray2)
.flatMap(Arrays::stream).distinct().sorted().toArray(String[]::new);
Arrays.stream(testArray3).forEach(System.out::println);
//coffee
//juice
//lemonade
//tea
//water
Related
I have a question about how to return the list of sorted anagrams that are placed adjacently in the indexes of a single array. To clarify this:
Array sortedAnagrams:
sortedAnagrams[0] = asp
sortedAnagrams[1] = pas
sortedAnagrams[2] = code
sortedAnagrams[3] = coed
sortedAnagrams[4] = deco
sortedAnagrams[5] = France
From this example, it is clear that my indices "2","3", & "4" have the highest occurring anagram. How do I write a method where I can say these indices contain the highest occurring anagram?
I started of doing this but I don't know how it should continue.
public static String[] getLargestAnagramGroup(String[] stringList){
for (int i = 0; i < stringList.length; i++) {
int j = i + 1;
if (AnagramUtil.areAnagrams(stringList[i],stringList[j]) == true) {
j++;
} else {
i = j;
}
}
return null; // for now
public static void main(String[] args) {
String[] ListOfSortedAnagrams = new String[] {"asp", "pas", "code", "coed", "deco" , "France" }
System.out.print("Most occurring anagrams are: " + AnagramUtil.getLargestAnagramGroup(String[] ListOfSortedAnagrams));
Results:
Most occurring anagrams are: code, coed, deco
You could normalize strings for example sort chars in string and group them by this normalized value.
Have a look at :
public class Anagram {
public static void main(String[] args) {
String[] listAnagrams = new String[]{"asp", "pas", "code", "coed", "deco", "France"};
Map<String, List<String>> countMap = new HashMap<>();
for (String str : listAnagrams) {
String normalized = normalize(str);
List<String> strings = countMap.getOrDefault(normalized, new ArrayList<>());
strings.add(str);
countMap.put(normalized, strings);
}
Optional<Map.Entry<String, List<String>>> max = countMap.entrySet().stream()
.max(Comparator.comparingInt(entry -> entry.getValue().size()));
System.out.print("Most occurring anagrams are: " + max.get().getValue());
}
private static String normalize(String inputString){
char[] tempArray = inputString.toCharArray();
Arrays.sort(tempArray);
return new String(tempArray);
}
}
Output:
Most occurring anagrams are: [code, coed, deco]
PS: It could be refactored with stream group but I think it will be less readable.
Update:
Here is stream group version:
public class Anagram {
public static void main(String[] args) {
String[] listAnagrams = new String[]{"asp", "pas", "code", "coed", "deco", "France"};
Optional<Map.Entry<String, List<String>>> maxNormalised = Arrays.stream(listAnagrams)
.collect(Collectors.groupingBy(Anagram::normalize))
.entrySet().stream()
.max(Comparator.comparingInt(entry -> entry.getValue().size()));
System.out.print("Most occurring anagrams are: " + maxNormalised.get().getValue());
}
private static String normalize(String inputString){
char[] tempArray = inputString.toCharArray();
Arrays.sort(tempArray);
return new String(tempArray);
}
}
I stuck on a problem. I have a String array which is consist of String[]={"eat", "tea", "tan", "ate", "nat", "bat"} Now, I should segregated those word which have same letter on it and make a group. eat,tea,ate they have same letter in each word so this is a group. Group 2 should be tan,nat and Group3 should be bat. So I have to make a list of list to store those groups.
My approach:
To solve this problem I first find out the ascii values of each letter and then add those ascii values for a word. Like eat find out the ascii values of e,a,t and add them. I take this approach because if the letters are repeated in the words then they must have same ascii sum. After that I group them same Ascii sums and find out which words have those sums then they belongs to same group.
My progress
I find out ascii sums and put them in a hashmap. But then I could not group the same values. As I failed to group the ascii values I cannot find out the words.I have no clue how to proceed.
I also follow this posts
post1
post2
But there approach and my approach is not same. Also the questions are different from mine. I am discussing here about a different approach which is depend upon ASCII values.
My code:
public List<List<String>> groupAnagrams(String[] strs) {
ArrayList<Character>indivistr=new ArrayList<>();
ArrayList<Integer>dup=new ArrayList<>();
HashMap<Integer,Integer>mappingvalues=new HashMap<>();
for(int i=0;i<strs.length;i++){
int len=strs[i].length();
int sum=0;
for(int j=0;j<len;j++){
indivistr.add(strs[i].charAt(j));
int ascii=(int)strs[i].charAt(j);
sum=sum+ascii;
}
mappingvalues.put(i,sum);
}
}
One more approach
I transfer the map keys in a Arraylist and map values in a ArrayList. Something like that,
ArrayList<Integer>key_con=new ArrayList<
(mappingvalues.keySet());
ArrayList<Integer>val_con=new ArrayList<>(mappingvalues.values());
Then using two loops and put the same values into another list.
for(int k=0;k<val_con.size();k++){
for(int k1=k+1;k1<val_con.size();k1++){
if(val_con.get(k).equals(val_con.get(k1))){
dup.add(val_con.get(k1));
}
}
Now if I print dup output will be [314, 314, 314, 323] which is partially correct. It should be 314,314,314,323,323,311
This should get you started.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Main {
public static void main(String args[]) throws Exception {
String[] words ={"eat", "tea", "tan", "ate", "nat", "bat"};
for(List<String> list : groupAnagrams(words))
System.out.println(list);
}
public static List<ArrayList<String>> groupAnagrams(String[] words) {
List<ArrayList<String>> wordGroups = new ArrayList<ArrayList<String>>();
HashMap<Integer, ArrayList<String>> map = new HashMap<Integer, ArrayList<String>>();
for(String word : words) {
int sum = 0;
for(char c : word.toCharArray())
sum += c;
if(map.containsKey(sum))
map.get(sum).add(word);
else {
ArrayList<String> list = new ArrayList<String>();
list.add(word);
map.put(sum, list);
}
}
for(ArrayList<String> list : map.values())
wordGroups.add(list);
return wordGroups;
}
}
This program will work for small scale things such as this but consider the following input data:
{"a", "#!"}
The sum of these Strings are both 97.
Since you're using ASCII values to find anagrams you might run into a case such as this. This isn't a particularly pressing matter until you start messing around with lowercase letters and capitals. Easy fix for that is just a String.ToUpperCase() and map the symbols to huge numbers and you're good to go.
For posterity:
public class anagrams {
public static void main(String args[]) {
int numberOfAnagrams = 0;
String[] stringArray = {"eat", "tea", "tan", "ate", "nat", "bat", "plate", "knot"};
List<String> stringList = Arrays.asList(stringArray);
for(int i = 0; i < stringList.size() - 1; i++) {
for(int j = i + 1; j < stringList.size(); j++) {
if(isAnagram(stringList.get(i), stringList.get(j))) {
System.out.println(stringList.get(i) + " " + stringList.get(j));
numberOfAnagrams += 2;
}
}
}
System.out.println(numberOfAnagrams);
}
private static boolean isAnagram(String s1, String s2) {
// In order for two String to be anagrams, they must have the same length.
if(s1.length() != s2.length()) {
return false;
}
// If s2 does not contain even one of s1's chars return false.
for(int i = 0; i < s1.length(); i++) {
if(!s2.contains("" + s1.charAt(i))) {
return false;
}
}
return true;
}
}
Based on the asci approach I have made a working code
public static void main(String[] args) {
String[] values ={"eat", "tea", "tan", "ate", "nat", "bat"};
Map<Integer, List<String>> resultMap = new HashMap<Integer, List<String>>();
for (String value : values) {
char[] caharacters = value.toLowerCase().toCharArray();
int asciSum = 0;
for (char character : caharacters) {
asciSum = asciSum + (int)character;
}
System.out.println(asciSum);
if(resultMap.containsKey(asciSum)) {
resultMap.get(asciSum).add(value);
}else {
List<String> list = new ArrayList<String>();
list.add(value);
resultMap.put(asciSum, list);
}
}
System.out.println(resultMap);
}
This will give result
{323=[tan, nat], 311=[bat], 314=[eat, tea, ate]}
but if we encounter diff characters with same asci value sum like 10+11 = 20+1
below code will work where based on the sorted string we make the result map
public static void main(String[] args) {
String[] values ={"eat", "tea", "tan", "ate", "nat", "bat"};
Map<String, List<String>> resultMap = new HashMap<String, List<String>>();
for (String value : values) {
char[] caharacters = value.toLowerCase().toCharArray();
Arrays.sort(caharacters);
String sortedValue = new String(caharacters);
System.out.println(sortedValue);
if(resultMap.containsKey(sortedValue)) {
resultMap.get(sortedValue).add(value);
}else {
List<String> list = new ArrayList<String>();
list.add(value);
resultMap.put(sortedValue, list);
}
}
System.out.println(resultMap);
}
This will return
{aet=[eat, tea, ate], abt=[bat], ant=[tan, nat]}
I have fixed the comments and edits provided.
Here's my idea, first I would create a class that will store the original string and it's sorted version:
class Anagram {
String s;
String sorted;
}
Then I map the input to my list of Anagram:
List<Anagram> collect = Arrays.stream(strs)
.map(a -> new Anagram(a, Arrays.stream(a.split(""))
.sorted()
.reduce(String::concat).get()))
.collect(Collectors.toList());
Then I just group the obtained list by sorted string:
Map<String, List<Anagram>> groupBy = collect
.stream()
.collect(Collectors.groupingBy(Anagram::getSorted));
Now you have the lists with grouped anagrams, just extract from them the original string:
List<List<String>> result = new ArrayList<>();
for(List<Anagram> list : collect1.values()) {
List<String> myList = list.stream().map(Anagram::getS).collect(Collectors.toList());
result.add(myList);
}
So I am trying to create small Java program where names from array are paired. But I don't know how to proceed. I have array with names and the object is to pair two names randomly to make a team. There should be some statement so certain pairs couldn't be made: Miller & James can't be in the same team and no dublicates. How do I do this?
Example output:
James & Hal
import java.util.Random;
public class Teams {
public static void main (String [] args) {
String [] arr = {"John", "James", "George", "Miller", "Hal", "Dan"};
Random random = new Random();
int select = random.nextInt(arr.length);
int selectSecond = random.nextInt(arr.length);
System.out.println(arr[select]);
System.out.println(arr[selectSecond]);
}
}
You can delete the first chosen name from the array and then choose again to get the second one. To delete an element from an array see Removing an element from an Array (Java). Here is one possible implementation (but I didn't test it):
public static void main (String [] args) {
String [] arr = {"John", "James", "George", "Miller", "Hal", "Dan"};
Random random = new Random();
int select = random.nextInt(arr.length);
arr = removeElements(arr, arr[select]);
int selectSecond = random.nextInt(arr.length);
System.out.println(arr[select]);
System.out.println(arr[selectSecond]);
}
// import java.util.LinkedList;
public static String[] removeElements(String[] input, String deleteMe) {
List result = new LinkedList();
for(String item : input)
if(!deleteMe.equals(item))
result.add(item);
return (String[]) result.toArray(input);
}
I would like to use Collections.shuffle instead, and a do while loop like so :
String[] arr = {"John", "James", "George", "Miller", "Hal", "Dan"};
List<String> list = Arrays.asList(arr);
String name1, name2;
do {
Collections.shuffle(list);
name1 = list.get(0);
name2 = list.get(1);
} while ((name2.equals("Miller") && name1.equals("James"))
|| (name1.equals("James") && name2.equals("Miller")));
System.out.println(String.format("%s & %s", name1, name2));
With this solution you don't need to check if the both names are same or not, you just need to check if the two name not equals in the same pair to Miller and James
It will depend which perspective you want to attack here. If you just want to "do the job", you have an extensive list of possibilities (as we already have here), but I would just take care with readability:
public class Teams {
private static String[][] teamsToAvoid = {{"James", "Miller"}, {"John", "Hal"}};
private static String[][] teamsFormed = new String[3][2];
public static void main(String[] args){
String[] names = {"John", "James", "George", "Miller", "Hal", "Dan"};
List<String> namesList = new ArrayList<>(Arrays.asList(names));
Collections.shuffle(namesList);
do {
formTeam(namesList, 0, 1);
} while(namesList != null && !namesList.isEmpty());
for(String[] team : teamsFormed){
System.out.println("Team: {" + team[0] + ", " + team[1] + "}");
}
}
private static void formTeam(List<String> namesList, int firstPlayerIndex, int secondPlayerIndex) {
if(isTeamPossible(namesList.get(firstPlayerIndex), namesList.get(secondPlayerIndex))){
String firstPlayer = namesList.get(firstPlayerIndex);
String secondPlayer = namesList.get(secondPlayerIndex);
teamsFormed[getFormedTeamNextIndex()] = new String[]{firstPlayer, secondPlayer};
namesList.remove(namesList.indexOf(firstPlayer));
namesList.remove(namesList.indexOf(secondPlayer));
} else {
formTeam(namesList, firstPlayerIndex, ++secondPlayerIndex);
}
}
private static boolean isTeamPossible(String player1, String player2) {
for(String[] teamToAvoid : teamsToAvoid){
if(Arrays.asList(teamToAvoid).contains(player1) && Arrays.asList(teamToAvoid).contains(player2)){
return false;
}
}
return true;
}
private static int getFormedTeamNextIndex() {
for(int i = 0; i < teamsFormed.length; i++){
if(teamsFormed[i][0] == null && teamsFormed[i][1] == null)
return i;
}
return 0;
}
}
Doing this you will prevent the same pair in different order and remove those players from the list (preventing their reuse).
I would pay attention when removing from list directly by index also, because when you remove one item the index for items after that one change.
Here is what I'm trying to use. The method .length doesn't work for anything I try, so I'm not even sure where to begin.
import java.util.ArrayList;
public class LengthsOfStrings {
public static ArrayList<Integer> lengths(ArrayList<String> list) {
ArrayList<Integer> lengthList = new ArrayList<Integer>();
for (int nums: lengthList) {
System.out.println(nums.length());
}
return lengthList;
}
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("Ciao");
list.add("Moi");
list.add("Benvenuto!");
list.add("badger badger badger badger");
ArrayList<Integer> lengths = lengths(list);
System.out.println("The lengths of the Strings: " + lengths);
}
}
You are trying to iterate through a single int instead of the strings array. Change
for (int nums: lengthList) {
System.out.println(nums.length());
}
to
for (String str: list) { // loop through the list of strings
lengthList.add(str.length()); // store the individual length of each string
}
so as to loop through the list of strings, collect the length of each string & store it int the Arraylist that you return later.
In the following code:
ArrayList<Integer> lengthList = new ArrayList<Integer>();
for (int nums: lengthList) {
System.out.println(nums.length());
}
You are creating an ArrayList<Integer> lengthList which is empty and trying to iterate over it.
I think you want to iterate over list something like this:
for (String s: list) {
lengthList.add(s.length());
System.out.println(s.length());
}
and add length() of each String to lengthList in each iteration.
Here in your code you need to update at 2 places:
1) In lengths method you are passing list(ArrayList<String> list), but you are not iterating over that you. You have to iterate over this list.
2) In the for loop you have made the variable as int, while the list is of type String. So update your code like below :
public static ArrayList<Integer> lengths(ArrayList<String> list) {
for (String nums: list) {
System.out.println(nums.length());
}
return lengthList;
}
For Java 8 user
public static void main(final String[] args) {
List<String> strings = Arrays.asList("Hi", "Hello", "how r u?");
List<Integer> lengthList = lengths(strings);
lengthList.forEach(System.out::println);
}
public static List<Integer> lengths(List<String> list) {
return list.stream().mapToInt(s -> s.length()).boxed()
.collect(Collectors.toList());
//OR
return list.stream().mapToInt(String::length).boxed()
.collect(Collectors.toList());
}
I am new to java, and am confused with the problem.
This is what I came up so far.
I am still working on it, if I come up with any progress, I'll post it here.
public class charArray {
public static void main(String[] args) {
String[] strArray = new String[] {"apple", "ball", "cat", "apple", "ball", "apple"};
//output should be ["apple", "ball"]
checkDuplicate(strArray);
}
public static String[] checkDuplicate(String[] strArray){
String[] newArray = new String[]{};
for(int i = 0; i < strArray.length; i++){
for(int j = 0; j < i; j++){
if (strArray[i].equals(srtArray[j])){
newArray = strArray[i];
}
}
}
return newArray[];
}
}
New progress:
Ok, my mediocre head has gone this far: (and the solution works)
It prints out the unique array of Duplicate elements.
But now I need to implement the same code, by calling a method.
Any help is appreciated.
import java.util.*;
public class setChar {
public static void main(String[] args) {
String[] strArray = new String[] {"apple", "ball", "cat", "apple", "ball", "apple"};
Set set = new HashSet();
Set uniqueSet = new HashSet();
for(int i = 0; i < strArray.length ; i++ ){
boolean b = set.add(strArray[i]);
if(b == false){
uniqueSet.add(strArray[i]);
}
}
Iterator it = uniqueSet.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
The output is:
ball
apple
Finally implemented with method, with proper return type.
Please let me know, if this can be further optimized.
Thank all for you suggestions. Here is the working code:
public class retUnique {
public static void main(String[] args) {
String[] strArray = new String[] {"apple", "ball", "cat", "apple", "ball", "apple"};
System.out.println(printUnique(strArray));
}
public static Set<String> printUnique(String[] strArray){
Set<String> set = new HashSet<String>();
Set<String> uniqueSet = new HashSet<String>();
for(int i = 0; i < strArray.length ; i++ ){
boolean b = set.add(strArray[i]);
if(b == false){
uniqueSet.add(strArray[i]);
}
}
return(uniqueSet);
}
}
One easy option is to use a Set like container instead of an array. It will automatically ensure that only unique values are present.
You can look at examples of TreeSet and HashSet.
Something like this should work I believe. Been a while since I coded in Java so if anyone wants to make edits, please do.
public String[] returnDups(String[] strArray) {
Set<String> set = new HashSet<String>(strArray);
return set.toArray(new String[0]);
}
But what everyone has been suggesting is the correct idea. Sets make it really easy to remove duplicates so you should utilize them. Let's not reinvent the wheel.
To detect dupplicates, if that is your question, add all elememts of the array to a Set, if set.add() returns false, then it is a dupplicate, so you can add this elemen to your result list of dupplictes.
Or if your question is meaning to return the values without duplicates, then you can retirnthe set, or convert the set to list before returning.