I have an 2D-array like this in java
transmission communication tv television
approach memorycode
methodact
I need to get all combinations like:
{transmission,approach,methodact},{transmission,memorycode,methodact},{communication,approach,methodact},...
Can someone provide an example that will work for nXn arrays, even if it has only two rows?
This should do the trick:
static Set<List<String>> allComb(String[][] opts) {
Set<List<String>> results = new HashSet<List<String>>();
if (opts.length == 1) {
for (String s : opts[0])
results.add(new ArrayList<String>(Arrays.asList(s)));
} else
for (String str : opts[0]) {
String[][] tail = Arrays.copyOfRange(opts, 1, opts.length);
for (List<String> combs : allComb(tail)) {
combs.add(str);
results.add(combs);
}
}
return results;
}
This code in JavaScript can help you:
var sampleArray = [["transmission","communication","tv","television"], ["approach","memorycode"], ["methodact"]];
var GetAllCombinations = function(array2d)
{
var ret=[];
var fn = function(arr,index,cur)
{
var ret = [];
for (var i=0; i<arr[index].length; i++)
{
var x = cur.slice(0);
x.push(arr[index][i]);
if (index == arr.length-1)
ret.push(x);
else
ret = ret.concat(fn(arr,index+1,x));
}
return ret;
};
return fn(array2d,0,[]);
}
console.log(GetAllCombinations(sampleArray));
It builds all combinations starting with a given array, iterates over all the options for that level and call it recursively, then concatenate it with the result.
Related
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;
}
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.
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.
Below are the 2 ways to remove null values, which one is the best approach?
public static String[] clean(final String[] v) {
List<String> list = new ArrayList<String>(Arrays.asList(v));
list.removeAll(Collections.singleton(null));
return list.toArray(new String[list.size()]);
}
public static String[] clean(final String[] v) {
List<String> list = new ArrayList<String>(v.length);
for (String aString : v)
{
if (aString != null)
{
list.add(aString);
}
}
return list.toArray(new String[list.size()]);
}
For removing null values from a single string, I would use a regular expression like this,
private static Pattern pattern = Pattern.compile("(?i)[(\\[{]?null[)\\]}]?");
public static String removeNullString(String value) {
if (StringUtils.isEmpty(value)) {
return StringUtils.EMPTY;
}
Matcher matcher = pattern.matcher(value);
return matcher.replaceAll(StringUtils.EMPTY);
}
It covers up all "null" and empty character from string.
For removing null value from a string array in Java 7,
String[] firstArray = {"test1", "", "test2", "test4", "", null};
List<String> list = new ArrayList<String>();
for(String s : firstArray) {
if(s != null && s.length() > 0) {
list.add(s);
}
}
firstArray = list.toArray(new String[list.size()]);
For removing null value from a string array in Java 8,
String[] firstArray = {"test1", "", "test2", "test4", "", null};
firstArray = Arrays.stream(firstArray)
.filter(s -> (s != null && s.length() > 0))
.toArray(String[]::new);
Performance wise, it is usually better to minimize calls outside of the scope of the current code block (ie method). Also, since memory allocation is relatively slow compared most other instructions, avoiding object creation is typically a goal. The best I can come up with in terms of performance (I chose to make it flexible enough to take any type of array):
public <T> T[] removeNulls(Class<T> type, final T[] original){
// first, shift all non-null instances to the head, all nulls to the end.
int nonNullCount=0;
T tempT = null;
for(int i=0; i < original.length; i++){
if(original[i] != null){
nonNullCount++;
}else if(i != original.length - 1){
// Swap the next non-null value with this null value
int j = i + 1;
// In case there are multiple null values in a row
// scan ahead until we find the next non-null value
while(j < original.length && (tempT = original[j]) == null){
j++;
}
original[nonNullCount] = tempT;
if(tempT != null){
nonNullCount++;
}
if(j < original.length){
original[j] = null;
}
i = j - 1;
}
}
// The case where there are no nulls in the array
if(nonNullCount == original.length){
return original;
}
final T[] noNulls = (T[]) Array.newInstance(type,nonNullCount);
System.arraycopy(original,0,noNulls,0,nonNullCount);
return noNulls;
}
But I'm not sure why you would want this complexity over the 3 or 4 lines to do the same thing when performance is not likely to be an issue. You would need to have HUGE arrays to see any benefit (if any) between my code and your clean example.
in Java 8 you should be able to do something like:
List<String> list = new ArrayList<String>(Arrays.asList(v));
list.removeIf(Objects::isNull);
return list.toArray(new String[list.size()]);
if you want to do it in same space i will suggest the follwing solution. But final array will also be having same size. I mean it will not shrink in size but all elements will get aggregated in same order.
public static void removeNullFromArray(String[] args) {
int location = 0;
for(int i=0; i<args.length; i++){
String arg = args[i];
if(arg!=null){
if(location<i){
args[location] = arg;
args[i] = null;
}
location++;
}
}
}
Java 8 code using streams and lambda. Filters non-nulls from an array and converts to a list.
Arrays.stream(arr).filter(Objects::nonNull).collect(Collectors.toList());
/** 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);
}
}