Find common elements between two string arrays (even duplicates) - java

Ok, so I'm making a discord bot, and im dumb.
So if the solution of the game is: [":star:", ":star:", ":star:", ":star:"]
And I enter [":star:",":clubs:", ":star:", ":star:"]
I need the common string array to be: [":star:",":star:",":star:"]
This is what i tried:
private List<String> findCommonElement(String[] a, String[] b) {
List<String> commonElements = new ArrayList<>();
for (String s1 : a) {
for (String s2 : b) {
if (s1.equals(s2)) {
commonElements.add(s1);
break;
}
}
}
return commonElements;
}
I realize its checking each elements position with the others array position, but I don't know. Make it not nested?

Use a Set and it will prevent the duplicate values from being added
Set<String> commonElements = new HashSet<>();
for (String s1 : a) {
for (String s2 : b) {
if (s1.equals(s2)) {
commonElements.add(s1);
break;
}
}
}
return commonElements;

In the if condition, before setting the break, you can simply change the b array at that position to another string that will cause the if condition to be false for that position in array b when the nested for loop gets called again.
private List<String> findCommonElement2(String[] a, String[] b) {
List<String> commonElements = new ArrayList<>();
for(int i = 0; i < a.length; i++) {
for(int x = 0; x < b.length; x++) {
if(a[i].equals(b[x])) {
commonElements.add(a[i]);
b[x] = "ignore";
break;
}
}
}
return commonElements;
}

Related

Remove duplicates in 2d array

I want to remove duplicate row in a 2d array . i tried the below code .but it is not working . please help me .
Input :
1,ram,mech
1,ram,mech
2,gopi,csc
2.gopi,civil
output should be :
1,ram,mech
2,gopi,csc
2.gopi,civil
Code :
package employee_dup;
import java.util.*;
public class Employee_dup {
public static void main(String[] args)
{
boolean Switch = true;
System.out.println("Name ID Dept ");
String[][] employee_t = {{"1","ram","Mech"},{"1","siva","Mech"},{"1","gopi","Mech"},{"4","jenkat","Mech"},{"5","linda","Mech"},{"1","velu","Mech"}};
int g = employee_t[0].length;
String[][] array2 = new String[10][g];
int rows = employee_t.length;
Arrays.sort(employee_t, new sort(0));
for(int i=0;i<employee_t.length;i++){
for(int j=0;j<employee_t[0].length;j++){
System.out.print(employee_t[i][j]+" ");
}
System.out.println();
}
List<String[]> l = new ArrayList<String[]>(Arrays.asList(employee_t));
for(int k = 0 ;k < employee_t.length-1;k++)
{
if(employee_t[k][0] == employee_t[k+1][0])
{
System.out.println("same value is present");
l.remove(1);
array2 = l.toArray(new String[][]{});
}
}
System.out.println("Name ID Dept ");
for(int i=0;i<array2.length;i++){
for(int j=0;j<array2[0].length;j++){
System.out.print(array2[i][j]+" ");
}
System.out.println();
}
}
}
class sort implements Comparator {
int j;
sort(int columnToSort) {
this.j = columnToSort;
}
//overriding compare method
public int compare(Object o1, Object o2) {
String[] row1 = (String[]) o1;
String[] row2 = (String[]) o2;
//compare the columns to sort
return row1[j].compareTo(row2[j]);
}
}
First I sorted the array based on column one ,then tried to remove duplicates by checking the first column elements and seconds column elements but it is not removing the required column but remove other columns.
You may give this solution a try:
public static void main(String[] args) {
String[][] employee_t = {
{"1","ram","Mech"},
{"1","ram","Mech"},
{"1","siva","Mech"},
{"1","siva","Mech"},
{"1","gopi","Mech"},
{"1","gopi","Mech"} };
System.out.println("ID Name Dept");
Arrays.stream(employee_t)
.map(Arrays::asList)
.distinct()
.forEach(row -> System.out.printf("%-3s%-7s%s\n", row.get(0), row.get(1), row.get(2)));
}
Output
ID Name Dept
1 ram Mech
1 siva Mech
1 gopi Mech
How it works: comparing arrays does rely on instance equality and not on comparing contained elements by equals. Hence converting each row of your 2D array into a List will enable you to compare lists, which takes equals of the elements contained into account.
The Java Stream API does provide a method distinct which relies on equals and will remove all duplicates for you.
Based on your code. Maybe it is not the BEST solution but it works.
public static void main(String[] args) {
System.out.println("Name ID Dept ");
// I added duplicated rows
String[][] inputArray = {
{ "1", "ram", "Mech" },
{ "1", "siva", "Mech" },
{ "1", "gopi", "Mech" },
{ "1", "gopi", "Mech" },
{ "4", "jenkat", "Mech" },
{ "5", "linda", "Mech" },
{ "1", "velu", "Mech" },
{ "1", "velu", "Mech" }
};
// I will add all rows in a Set as it doesn't store duplicate values
Set<String> solutionSet = new LinkedHashSet<String>();
// I get all rows, create a string and insert into Set
for (int i = 0 ; i < inputArray.length ; i++) {
String input = inputArray[i][0]+","+inputArray[i][1]+","+inputArray[i][2];
solutionSet.add(input);
}
// You know the final size of the output array
String[][] outputArray = new String[solutionSet.size()][3];
// I get the results without duplicated values and reconvert it to your format
int position = 0;
for(String solution : solutionSet) {
String[] solutionArray = solution.split(",");
outputArray[position][0] = solutionArray[0];
outputArray[position][1] = solutionArray[1];
outputArray[position][2] = solutionArray[2];
position++;
}
System.out.println("Name ID Dept ");
for (int i = 0; i < outputArray.length; i++) {
for (int j = 0; j < outputArray[0].length; j++) {
System.out.print(outputArray[i][j] + " ");
}
System.out.println();
}
}
I have posted what I think is a readable and easy to maintain solution.
I decided to use distinct from Stream which is part of Java 8
Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream. - https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#distinct--
Main.class
class Main {
public static void main(String[] args)
{
//Create a list of Employee objects
List<Employee> employeeList = new ArrayList<Employee>();
Employee e1 = new Employee(1, "ram", "mech");
Employee e2 = new Employee(1, "ram", "mech");
Employee e3 = new Employee(2, "gopi", "csc");
Employee e4 = new Employee(2, "gopi", "civil");
employeeList.add(e1);
employeeList.add(e2);
employeeList.add(e3);
employeeList.add(e4);
System.out.println("Before removing duplicates");
employeeList.stream().forEach(System.out::println);
//This is where all the magic happens.
employeeList = employeeList.stream().distinct().collect(Collectors.toList());
System.out.println("\nAfter removing duplicates");
employeeList.stream().forEach(System.out::println);
}
}
Output:
Before removing duplicates
Employee [valA=1, valB=ram, valC=mech]
Employee [valA=1, valB=ram, valC=mech]
Employee [valA=2, valB=gopi, valC=csc]
Employee [valA=2, valB=gopi, valC=civil]
After removing duplicates
Employee [valA=1, valB=ram, valC=mech]
Employee [valA=2, valB=gopi, valC=csc]
Employee [valA=2, valB=gopi, valC=civil]
Employee.class
//This is just a regular POJO class.
class Employee {
int valA;
String valB, valC;
public Employee(int valA, String valB, String valC){
this.valA = valA;
this.valB = valB;
this.valC = valC;
}
public Employee(Employee e) {
this.valA = e.valA;
this.valB = e.valB;
this.valC = e.valC;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + valA;
result = prime * result + ((valB == null) ? 0 : valB.hashCode());
result = prime * result + ((valC == null) ? 0 : valC.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof Employee && ((Employee)obj).hashCode() == this.hashCode()){
return true;
}
return false;
}
#Override
public String toString() {
return "Employee [valA=" + valA + ", valB=" + valB + ", valC=" + valC + "]";
}
}
Pre Java - 8 solution. May not be the best way. But a quick solution which works..
String[][] records = {
{"1","ram","Mech"},
{"1","ram","Mech"},
{"1","gopi","csc"},
{"1","gopi","civil"} };
List<String[]> distinctRecordsList = new ArrayList<String[]>();
for(String[] record : records){
if(distinctRecordsList.size()>0){
boolean sameValue = false;
for(String[] distinctRecord : distinctRecordsList){
int distinctRecordFields = distinctRecord.length;
if(record.length==distinctRecordFields){
for(int k=0;k<distinctRecordFields;k++){
sameValue = record[k].equalsIgnoreCase(distinctRecord[k]);
if(!sameValue)
break;
}
}else
throw new Exception("Can't compare the records");
}
if(!sameValue)
distinctRecordsList.add(record);
}else if(distinctRecordsList.size()==0)
distinctRecordsList.add(record);
}
Object[] distRecObjects = distinctRecordsList.toArray();
String[][] distinctRecordsArray = new String[distRecObjects.length][];
int i=0;
for(Object distRecObject : distRecObjects){
distinctRecordsArray[i] = (String[]) distRecObject;
i++;
}
Contrary to some other answers I will try to explain what went wrong in your own code and how to fix it within your code (I agree very much with kkflf that an Employee class would be a huge benefit: it’s more object-oriented and it will help structure the code and give better overview of it).
The issues I see in your code are:
You are not removing the correct element when you detect a duplicate, but always the element at index 1 (the second element since indices count from 0). This isn’t trivial, though, because indices shift as you remove elements. The trick is to iterate backward so only indices that you are finished with shift when you remove an element.
You are using == to compare the first element of the subarrays you are comparing. If you wanted to compare just the first element, you should use equals() for comparison. However, I believe you want to compare the entire row so 2,gopi,csc and 2.gopi,civil are recognized as different and both preserved. Arrays.equals() can do the job.
You need to create array2 only after the loop. As your code stands, if no duplicates are detected, arrays2 is never created.
So your loop becomes:
for (int k = employee_t.length - 1; k >= 1; k--)
{
if (Arrays.equals(employee_t[k], employee_t[k - 1]))
{
System.out.println("same value is present");
l.remove(k);
}
}
array2 = l.toArray(new String[][]{});
This gives you the output you asked for.
Further tips:
Your comparator only compares one field in the inner arrays, which is not enough to guarantee that identical rows come right after each other in the sorted array. You should compare all elements, and also require that the inner arrays have the same length.
Use generics: class Sort extends Comparator<String[]>, and you won’t need the casts in compare()
According to Java naming conventions it should be class EmployeeDup, boolean doSwitch (since switch is a reserved word) and class Sort.
You are not using the variables Switch and rows; delete them.
I have wrote a solution for me. This may not be the best but it works.
public static String[][] removeDuplicate(String[][] matrix) {
String[][] newMatrix = new String[matrix.length][matrix[0].length];
int newMatrixRow = 1;
for (int i = 0; i < matrix[0].length; i++)
newMatrix[0][i] = matrix[0][i];
for (int j = 1; j < matrix.length; j++) {
List<Boolean> list = new ArrayList<>();
for (int i = 0; newMatrix[i][0] != null; i++) {
boolean same = true;
for (int col = 2; col < matrix[j].length; col++) {
if (!newMatrix[i][col].equals(matrix[j][col])) {
same = false;
break;
}
}
list.add(same);
}
if (!list.contains(true)) {
for (int i = 0; i < matrix[j].length; i++) {
newMatrix[newMatrixRow][i] = matrix[j][i];
}
newMatrixRow++;
}
}
int i;
for(i = 0; newMatrix[i][0] != null; i++);
String finalMatrix[][] = new String[i][newMatrix[0].length];
for (i = 0; i < finalMatrix.length; i++) {
for (int j = 0; j < finalMatrix[i].length; j++)
finalMatrix[i][j] = newMatrix[i][j];
}
return finalMatrix;
}
This method will return a matrix without any duplicate rows.

Sort Array with Two Exceptions in Java

I have an array of strings and I need to sort it before I return it. The issue is that two of those values must come first. I tried a few things (including what is below), but I can't seem to figure it out.
What I have below clearly doesn't work because I sort it twice in some cases. I know I can change the array to a list and then use Collections.reverse, but is there a better way that doesn't involve changing structures? I added a simple example below
public static String[] getStrings() {
String[] array = {"d","a","c","e","b"};
boolean first = false;
boolean second = false;
int left = 0;
for (int right = 0; right < array.length; right++) {
if (array[right].equals("e")){
first = true;
array[right] = array[left];
array[left] = "e";
left++;
}
}
if (first) {Arrays.sort(array, left, array.length);}
left = 0;
for (int right = 0; right < array.length; right++) {
if (array[second].equals("c")){
second = true;
array[right] = array[left];
array[left] = "c";
left++;
}
}
if (second) {Arrays.sort(array, left, array.length);}
if (!first && !second) {Arrays.sort(array);}
}
return array;
}
EDIT
Using the array in the example d,a,c,e,b. After the sorting it should be c,e,a,b,d
The two exceptions alphabetically, following the rest of the array alphabetically as well.
You can use the Java 8 Stream API.
final String[] array = {"d","a","c","e","b"};
final Set<String> search = Stream.of("c", "e").collect(toSet());
final String[] result = Stream.concat(
Stream.of(array).filter(search::contains).sorted(),
Stream.of(array).filter(s -> !search.contains(s)).sorted()
).toArray(String[]::new);
The first part selects the "c" and "e" strings and sort them individually, then anything that is not "c" or "e" is selected and sorted individually. Finally, the two streams are concatenated into an array.
How about implementing custom Comparator?
String[] array = {"d","a","c","e","b"};
Arrays.sort(array, new Comparator<String> () {
int compare(String s1, String s2) {
if (firstOne.equals(s1) && firstOne.equals(s2)) {
return 0;
} else if (firstOne.equals(s1) {
return -1;
} else if (firstOne.equals(s2)) {
return 1;
}
if (secondOne.equals(s1) && secondOne.equals(s2)) {
return 0;
} else if (secondOne.equals(s1) {
return -1;
} else if (secondOne.equals(s2)) {
return 1;
}
return s1.compareTo(s2);
});
Refer to
https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#sort(T[],%20java.util.Comparator)
Take the indices of the elements that you don't want sort and move those elements to the front of the list, then sort the rest of the list.
public static String[] getString(String[] strArray, int... firstElems) {
// Move the elements that are not sorted to the front
int g = 0;
for (int f = 0; f < firstElems.length; f++, g++) {
String elem = strArray[g];
strArray[g] = strArray[firstElems[f]];
strArray[firstElems[f]] = elem;
}
// Sort the rest
Arrays.sort(strArray, g, strArray.length);
return strArray;
}
There is short solution based #ikicha's and Java 8:
final String first = "c", second = "e";
Arrays.sort(array, (i, j) -> {
if (i.equals(first) || (i.equals(second) && !j.equals(first))) {
return -1;
} else {
return i.compareTo(j);
}
});
Why don't you sort it first, then lookup the two values, and shift them upfront?
Worst case would be n*log(n)+2n.

Getting data from a given String separated by (,,-) in java

I am having a String like this "5006,3030,8080-8083".
I want each element separately from the String:
5006
3030
8080
8081
8082
8083
Here's my code:
int i=0,j=0;
String delim = "[,]";
String hyphon = "[-]";
String example = "5006,3030,8080-8083";
String p[] = example.split(delim);
int len = p.length;
for(i=0;i<len;i++) {
String ps[]=p[i].split(hyphon);
if(ps.length>1) {
int start = Integer.parseInt(ps[0]);
int finish = Integer.parseInt(ps[1]);
int diff = finish-start+1;
for(j=0;j<diff;j++) {
System.out.println(start+j);
}
} else if(ps.length==1) {
System.out.println(ps[0]);
}
}
Is there any better solution or any class that simplifies my code?
I also want the numbers in a ascending order.
Try this code :
public static void main(String[] args) {
String input = "5006,3030,8080-8083";
List<Integer> list = new ArrayList<Integer>();
String[] numbers = input.split(",");
for (String s : numbers) {
if (s.contains("-")) {
String[] range = s.split("-");
int from = Integer.parseInt(range[0]);
int to = Integer.parseInt(range[1]);
for (int i = from; i <= to; i++) {
list.add(i);
}
}
else {
list.add(Integer.parseInt(s));
}
}
System.out.println("in asc order");
Collections.sort(list);
System.out.println(list.toString());
System.out.println("in desc order");
Collections.reverse(list);
System.out.println(list.toString());
}
My output :
in asc order
[3030, 5006, 8080, 8081, 8082, 8083]
in desc order
[8083, 8082, 8081, 8080, 5006, 3030]
I also want the numbers in a ascending order.
This adds an unexpected twist to your whole program, because once you realize that printing-as-you-go no longer works, you need to start almost from scratch.
The first thing to do is picking an appropriate representation. It appears that you represent ranges of integers, so start by defining a class for them:
class IntRange : Comparable<IntRange> {
private int low, high;
public int getLow() {return low;}
public int getHigh() {return high;}
public IntRange(int low, int high) {
// Add range check to see if low <= high
this.low = low; this.high = high;
}
public IntRange(int point) {low = high = point;}
#Override
public void print() {
for (int i = low ; i <= high ; i++) {
System.out.println(i);
}
}
#Override
public int compareTo(IntRange other) {
...
}
}
Now you can use your code to split on [,], then split on [-], construct IntRange, and put it into an ArrayList<IntRange>. After that you can use sort() method to sort the ranges, and print them in the desired order.
But wait, there is more to your problem than meets the eye. Think what would happen for input like this:
1,5,3-7,6
Where should 5 and 6 be printed? It is not good to print it before or after 3-7, so the trick is to remove points inside ranges.
But even that's not all: what do you do about this input?
1-5,3-7
You should print numbers 1 through 7, inclusive, but this would require merging two ranges. There is a good data structure for doing this efficiently. It is called a range tree. If your input is expected to be large, you should consider using range tree representation.
You are good to go; you can minimize the counter variables using enhanced for loop and while loop.
String example = "5006,3030,8080-8083";
String[] parts=example.split(",")
ArrayList<Integer> numbers = new ArrayList<Integer>();
for(String part: parts)
{
if(part.contains("-"))
{
String subParts[]=part.split("-");
int start = Integer.parseInt(subParts[0]);
int finish = Integer.parseInt(subParts[1]);
while(start <= finish)
{
numbers.add(start);
System.out.println(start++);
}
}
else {
System.out.println(part);
numbers.add(Integer.parseInt(part));
}
}
Integer[] sortedNumbers = new Integer[numbers.size()];
sortedNumbers = Arrays.sort(numbers.toArray(sortedNumbers));
Update (from comment):
Numbers are sorted now.
Try this
String str = "5006,3030,8080-8083";
String[] array = str.split(",");
String ans = "";
for(int i = 0; i < array.length; i++){
if(array[i].contains("-")){
String[] array2 = array[i].split("-");
int start = Integer.parseInt(array2[0]);
int end = Integer.parseInt(array2[array2.length - 1]);
for(int j = start; j <= end; j++){
ans = ans + j + ",";
}
}
else{
ans = ans + array[i] + ",";
}
}
System.out.print(ans);
This code assumes all integers are positive.
public static void main(String[] args) {
String testValue="5006,3030,8080-8083";
Integer[]result=parseElements(testValue);
for (Integer i:result){
System.out.println(i);
}
}
/**
* NumberList is a string of comma-separated elements that are either integers, or a range of integers of the form a-b.
* #param numberList
* #return all the integers in the list, and in ranges in the list, in a sorted list
*/
private static Integer[] parseElements(String integerList) {
ArrayList<Integer> integers=new ArrayList<Integer>();
String[] csvs=integerList.split(",");
for(String csv : csvs){
if(csv.contains("-")){
String[] range=csv.split("-");
Integer left=Integer.decode(range[0]);
Integer right=Integer.decode(range[1]);
for(Integer i=left;i<=right;i++){
integers.add(i);
}
} else {
integers.add(Integer.decode(csv));
}
}
Collections.sort(integers);
return integers.toArray(new Integer[0]);
}
Using Guava's functional idioms you can achive this declaratively, avoiding the verbose, imperative for-loops. First declare a tokenizing function which converts each token in the comma-delimited string into an Iterable<Integer>:
private static final Function<String, Iterable<Integer>> TOKENIZER =
new Function<String, Iterable<Integer>>() {
/**
* Converts each token (e.g. "5006" or "8060-8083") in the input string
* into an Iterable<Integer>; either a ContiguousSet or a List with a
* single element
*/
#Override
public Iterable<Integer> apply(String token) {
if (token.contains("-")) {
String[] range = token.trim().split("-");
return ContiguousSet.create(
Range.closed(Integer.parseInt(range[0]),
Integer.parseInt(range[1])),
DiscreteDomain.integers());
} else {
return Arrays.asList(Integer.parseInt(token.trim()));
}
}
};
then apply the function to the input:
String input = "5006,3030,8080-8083";
Iterable<String> tokens = Splitter.on(',').trimResults().split(input);
SortedSet<Integer> numbers = Sets.newTreeSet();
Iterables.addAll(numbers,
// concat flattens the Iterable<Iterable<Integer>>
// into an Iterable<Integer>
Iterables.concat(Iterables.transform(tokens, TOKENIZER)));
As all of the logic is basically coded into the Function, the client code only needs to tokenize the string into an Iterable<String> (with Splitter), apply the Function through Iterables.transform, flatten the result of the transformation using Iterables.concat and finally add the resulting Iterable<Integer> into a SortedSet<Integer> which keeps the numbers in ascending order.
with java 8 stream api :
public static void main(String[] args) {
String s = "5006,3030,8080-8083";
Arrays.stream(s.split(","))
.flatMap(el -> el.contains("-") ? rangeToStream(el) : Stream.of(Integer.valueOf(el)))
.sorted()
.forEachOrdered(e -> System.out.println(e));
}
private static Stream<? extends Integer> rangeToStream(String el) {
AtomicInteger[] bounds = Arrays.stream(el.split("-")).map(e -> new AtomicInteger(Integer.parseInt(e))).toArray(size -> new AtomicInteger[2]);
return Arrays.stream(new Integer[bounds[1].get() - bounds[0].get() + 1]).map(e -> bounds[0].getAndIncrement());
}
U can code something like this -
String s="5006,3030,8080-8083";
String s2[]=s.split(",");
List<Integer> li= new ArrayList<Integer>();
List<Integer> numbers= new ArrayList<Integer>();
for(int i=0;i<s2.length;i++){
if(s2[i].contains("-")){
li.add(i);
}
else{
numbers.add(Integer.parseInt(s2[i]));
}
}
for(Integer i:li){
String str=s2[i];
String strArr[]=str.split("-");
for(int j=Integer.parseInt(strArr[0]);j<=Integer.parseInt(strArr[1]);j++){
numbers.add(j);
}
}
Collections.sort(numbers);
for(Integer k:numbers){
System.out.println(k);
}
public static void main(String[] args)
{
String example = "5006,3030,8080-8083";
String[] splitString = example.split(",");
List<Integer> soretedNumbers = new ArrayList<>();
for(String str : splitString)
{
String[] split2 = str.split("-");
if(split2.length == 1)
{
soretedNumbers.add(Integer.parseInt(str));
}
else
{
int num1 = Integer.parseInt(split2[0]);
int num2 = Integer.parseInt(split2[1]);
for(int i = num1;i <= num2; i++)
{
soretedNumbers.add(i);
}
}
}
Collections.sort(soretedNumbers);
for(int i : soretedNumbers)
{
System.out.println(i);
}
}

How to deal with multiplicity when checking if an arraylist is a subset

I have two Arraylist and I want to check if one is a subset of the other (ordering is not important in the comparison).
The problem is: Lets say Ar1={e,e,r} and Ar2={e,r,b,d}. In my code it says Ar1 is a subset. But I want it to say false, cause Ar2 has only one e. How to do that?
public static void dostuff(String word1,String word2){
List<String> list1 = new ArrayList<String>();
List<String> list2 = new ArrayList<String>();
for (String character : word1.split("")) {
list1.add(character);
}
for (String character : word2.split("")) {
list2.add(character);
}
boolean sub = list1.containsAll(list2) || list2.containsAll(list1);
System.out.println(sub);
}
I think this may be what you want. Note that list2.remove(elem) returns true if an element was removed, and false if not.
public static boolean dostuff(String word1,String word2){
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<String> list3;
for (String character : word1.split("")) {
list1.add(character);
}
for (String character : word2.split("")) {
list2.add(character);
}
list3 = new ArrayList<>(list2);
boolean isSubset = true;
for (final String elem : list1) {
if (!list2.remove(elem)) {
isSubset = false;
break;
}
}
if (isSubset) {
return true;
}
for (final String elem : list3) {
if (!list1.remove(elem)) {
return false;
}
}
return true;
}
#Johdoe. The below logic may help you. you can optimize if you want.
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>();
list1.add("e");
list1.add("a");
list1.add("r");
list2.add("e");
list2.add("r");
list2.add("b");
list2.add("d");
list2.add("a");
System.out.println("list2 " + list2);
System.out.println("list1 " + list1);
Set<Integer> tempList = new HashSet<Integer>();
System.out.println(" containsAll " + list2.containsAll(list1));
for (int i = 0; i < list2.size(); i++) {
for (int j = 0; j < list1.size(); j++) {
if (list2.get(i).equals(list1.get(j))) {
tempList.add(i);
}
}
}
System.out.println(" tempList " + tempList);
System.out.println("list 1 is subset of list 2 "
+ (tempList.size() == list1.size()));
Note also that a mathematical, and java, set is unique, so be careful of using the term "subset".
You can use a frequency map to test if one list "has each element in another list, with the same or fewer occurrences". i.e. once you have your list you can convert it into a Map<T, Integer> to store the counts of each list element. The use of a map avoids mutating the original lists (which you would do if testing by removing elements from the master list as you encounter them):
public static <T> boolean isSublist(List<T> masterList, List<T> subList) {
Map<T, Integer> masterMap = new HashMap<T, Integer>();
for (T t : masterList) masterMap.put(t, 1 + masterMap.getOrDefault(t, 0));
Map<T, Integer> testMap = new HashMap<T, Integer>();
for (T t : subList) testMap.put(t, 1 + testMap.getOrDefault(t, 0));
for(Map.Entry<T, Integer> entry : testMap.entrySet()) {
if (masterMap.getOrDefault(entry.getKey(), 0) < entry.getValue()) return false;
}
return true;
}
getOrDefault is only available as of Java 8, but you can easily write your own method to take care of the same operation.
I have found a solution myself, please check of this is right, but i believe it is.
public static void dostuff(String word1, String word2) {
boolean sub = false;
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>();
ArrayList<String> list3 = new ArrayList<String>();
for (int i = 0; i < word1.length(); i++) {
list1.add(word1.split("")[i]);
}
for (int i = 0; i < word2.length(); i++) {
list2.add(word2.split("")[i]);
}
if (list1.size() >= list2.size()) {
for (String i : list2) {
if (list1.contains(i)) {
list1.remove(i);
list3.add(i);
}
}
if (list2.containsAll(list3) && list2.size() == list3.size()) {
sub = true;
}
} else if (list2.size() > list1.size()) {
for (String i : list1) {
if (list2.contains(i)) {
list2.remove(i);
list3.add(i);
}
if (list1.containsAll(list3) && list1.size() == list3.size()) {
sub = true;
}
}
}
System.out.println(sub);
}
You could use a couple of maps to store the frequency of each letter:
public static void dostuff(String word1, String word2) {
Map<String, Long> freq1 = Arrays.stream(word1.split("")).collect(
Collectors.groupingBy(Function.identity(), Collectors.counting()));
Map<String, Long> freq2 = Arrays.stream(word2.split("")).collect(
Collectors.groupingBy(Function.identity(), Collectors.counting()));
System.out.println(contains(freq1, freq2) || contains(freq2, freq1));
}
Where the contains method would be as follows:
private static boolean contains(Map<String, Long> freq1, Map<String, Long> freq2) {
return freq1.entrySet().stream().allMatch(
e1 -> e1.getValue().equals(freq2.get(e1.getKey())));
}
Test:
dostuff("eer", "erbd"); // {r=1, e=2}, {b=1, r=1, d=1, e=1}, false
dostuff("erbed", "eer"); // {b=1, r=1, d=1, e=2}, {r=1, e=2}, true
The idea is to use java 8 streams to create the frequencies map, and then, stream the entry set of both maps to compare all the elements and their frequencies. If all entries match, then it means that the second list contains all the elements of the first list with the same frequencies, regardless of the order.
In case the result is false for the first list, the check is performed the other way round as well, as per the question requirements.
Now that I understand that the order of the contents doesn't matter, you just want to know if all the characters of one string exists in another (with the same frequency) or vice versa.
Try this function, it'll check everything without having to call the method twice and without using streams:
public static boolean subsetExists(String s1, String s2) {
String temp = s2.replaceAll(String.format("[^%s]", s1), "");
char[] arr1 = s1.toCharArray();
char[] arr2 = temp.toCharArray();
Arrays.sort(arr1);
Arrays.sort(arr2);
boolean isSubset = new String(arr2).contains(new String(arr1));
if (!isSubset) {
temp = s1.replaceAll(String.format("[^%s]", s2), "");
arr1 = temp.toCharArray();
arr2 = s2.toCharArray();
Arrays.sort(arr1);
Arrays.sort(arr2);
isSubset = new String(arr1).contains(new String(arr2));
}
return isSubset;
}
You don't have to bother turning your Strings into Lists. What's happening is we're checking if all the letters in s1 exist in s2 or vice versa.
We removed characters that are not in s1 from s2 and stored that result in a temporary String. Converted both the temporary String and s1 into char[]s. We then sort both arrays and convert them back into Strings. We then can check if NEW SORTED temporary String contains() the NEW SORTED s1. If this result is false, then we apply the same logical check from s2 to s1.
Usage:
public static void main(String[] args) throws Exception {
String s1 = "eer";
String s2 = "bderz";
String s3 = "bderzzeee";
System.out.println(subsetExists(s1, s2));
System.out.println(subsetExists(s1, s3));
}
public static boolean subsetExists(String s1, String s2) {
String temp = s2.replaceAll(String.format("[^%s]", s1), "");
char[] arr1 = s1.toCharArray();
char[] arr2 = temp.toCharArray();
Arrays.sort(arr1);
Arrays.sort(arr2);
boolean isSubset = new String(arr2).contains(new String(arr1));
if (!isSubset) {
temp = s1.replaceAll(String.format("[^%s]", s2), "");
arr1 = temp.toCharArray();
arr2 = s2.toCharArray();
Arrays.sort(arr1);
Arrays.sort(arr2);
isSubset = new String(arr1).contains(new String(arr2));
}
return isSubset;
}
Results:
false
true
Here is a Working Solution
Check Demo
public static void main (String[] args) throws java.lang.Exception
{
dostuff("eer","erbd");
}
public static void dostuff(String word1, String word2) {
List<String> list1 = new ArrayList<String>();
for (String character : word1.split("")) {
list1.add(character);
}
boolean sub = true;
for (String character : word2.split("")) {
if (list1.remove(character)) {
if (list1.isEmpty()) {
break;
}
} else {
sub = false;
break;
}
}
System.out.println(sub);
}

Sorting String[][] unexpected output

I want to sort my String[][] with respect to second column. I tried this
public static String[][] sorting_minn(String[][] list){
double[] temp = new double[list.length];
String[][] tempf = list;
if(list[1][1]!=null){
for(int i = 0; i<list.length; i++){
if(list[i][2]==null){
break;
} else {
temp[i]=Double.parseDouble(list[i][2]);
}
}
Arrays.sort(temp);
for(int f = 0; f<list.length-1;f++){
for(int m = 0; m<list.length;m++){
if(list[m][2]!=null && Double.parseDouble(list[m][2])==temp[f]){
for(int n = 0; n<4; n++){
tempf[list.length-f-1][n]=list[m][n];
}
m = list.length;
}
}
}
}
return tempf;
}
As an output I get this: . I need suggestion on how to improve this code.
try something like:
Arrays.sort(list, new Comparator<String[]>() {
#Override
public int compare(String[] o1, String[] o2) {
String left = o1[1]!=null ? o1[1] : "";
String right = o2[1]!=null ? o2[1] : "";
return left.compareTo(right);
}
});
this treats nulls as empty strings, and exploits the fact that strings are comparable, although lexicographic. if you want the reverse order just do this instead:
right.compareTo(left)
if you want integer ordering you could parse an Integer out of both sides (Integer.MIN for null) and compare 2 Integers

Categories