Sorting which string is bigger in java , Array - java

I want to sort the strings in the array, by alphabetizing them, but I get an error with argument types.
public class BubbleSort {
public static String[] sortStringArray(String[] stringArray) {
int s = stringArray.length;
String temp;
for (int i = 0 ; i < s; i++) {
for (int j = 1; j < (s - i); j++) {
String a1 = stringArray[j - 1];
String b1 = stringArray[j];
int result = a1.compareTo(b1);
if (result > stringArray[j]) {
temp = stringArray[j - 1];
stringArray[j - 1] = stringArray[j];
stringArray[j] = temp;
}
}
}
return stringArray;
}
}

Since you're calling compareTo(Object) on Strings, you need to check then if the result is bigger than zero:
if (0 < result) { // i.e. a1 is smaller than b1
//swap values as usual
}

To sort a String array by natural ordering you can use Arrays.stream
eg:
String[] s = {"b", "c", "a", "aaa", "abc"};
s = Arrays.stream(s).sorted().toArray(String[]::new);
gives s= [a, aaa, abc, b, c]

if (result > stringArray[j])
result is an integer, stringarray[j] is a string.
You can't compare with integer like that, if your string is an integer like stinrgArray[j] value is "11" and you want to compare it you need to parse it first to integer:
if(result > Integer.parseInt(stringArray[j]))

Related

Insertion Sort Algorithm to Sort String[]

I have a question about sorting String[] arrays using the Insertion Sort Algorithm in Java. I do realize that my question may very well be easier to complete using a different algorithm, but I am attempting to learn how everything works with this one first.
Basically, I am attempting to sort an array of strings using the algorithm. To do this, I compare char values from the array of strings so I am able to use standard > and == operators because comparing values this way (like you would with ints) is naturally very simple.
I have a solution I am working through where I sort an array of strings by the first 2 char values found at each array index, but I am starting to realize that what I have done is not a very robust solution because strings in an array can easily have values that are 'longer' than each other which would not make my sorting very accurate for longer strings with similar values.
With that in mind, can someone suggest (going along with the code I wrote below) how I would go about dynamically comparing char values created from various strings to sort the original string value?
So...
A: ...I don't run into NullPointer Exceptions comparing values from different sized strings
B: ...every char value is compared from the string, irregardless of size, so I can sort the original array of strings accurately)
public String[] sortArrayOfStrings(String[] array){
//NOT COMPLETE, ONLY SORTS BASED ON FIRST & SECOND CHAR OF STRING INDEX
//BASED ON INSERTION SORT ALGORITHM
int length = array.length;
String value;
int index;
for(int a = 1; a < length; a++){
char currentCharValue = array[a].charAt(0);//USE '[a]' not '[index]'
value = array[a];
index = a;
if(currentCharValue == array[a - 1].charAt(0) ){//IF FIRST CHAR == PREVIOUS
while (index > 0 && array[index - 1].charAt(1) > array[index].charAt(1)){
array[index] = array[index - 1];
index = index - 1;
}
}else{
while (index > 0 && array[index - 1].charAt(0) > currentCharValue){
array[index] = array[index - 1];
index = index - 1;
}
}
array[index] = value;
}
return array;
}
Example array that works as expected because of 2 char check:
String[] arr = {"zz", "bb", "cb", "ba","za", "zb", "cz", "ab","aa"};
Example array that would fail to sort correctly because of extra chars:
String[] arr = {"bbz", "bba", "abz","abc"};
I know the above array fails to sort correctly because of the hardcoded 'check' of 2 chars, I am trying to remove the need to hardcode the check.
Try using the String.CompareTo(String s) method. It's a lot like the comparison operators that you have been using, except it will evaluate to an integer.
String str1 = "Cat";
String str2 = "Dog";
int sCompare = str1.CompareTo(str2);
if sCompare == 0, then the Strings are the "same"
if sCompare > 0, then str1 > str2 (alphabetically)
if sCompare < 0, then str2 > str1 (alphabetically)
Edit:
For clarity, in the case of the above example, sCompare would evaluate to a negative value.
If you really want to do it using chars comparsion the best way is to create separate method to compare these Strings.
Inside a isSmallerThan() while loop increments currentIndex until it's not out of bound for any argument and until chars are same.
Then if statement check whether currentIndex got out of bounds for at least one string, it can happen for inputs like e.g.:
(aaaaa, aa),
(aaabb, aaa),
(aaa, aaa).
Then we must decide what is smaller by length comparsion.
For the case of insertion sort algorithm we do not care that (aaa, aaa) are the same Strings, we can just return that this is false and it'll interrupt a while loop inside sortArrayOfStrings method.
Else we know that chars are different and we simply compare them.
String[] sortArrayOfStrings(String[] array){
int length = array.length;
String value;
int index;
for(int a = 1; a < length; a++){
value = array[a];
index = a;
while(index > 0 && isSmallerThan(value, array[index-1])) {
array[index] = array[index - 1];
--index;
}
array[index] = value;
}
return array;
}
boolean isSmallerThan(String left, String right) {
int curIndex = 0;
while (curIndex < left.length()
&& curIndex < right.length()
&& left.charAt(curIndex) == right.charAt(curIndex)){
++curIndex;
}
if (curIndex == left.length() || curIndex == right.length())
return left.length() < right.length();
else
return left.charAt(curIndex) < right.charAt(curIndex);
}
But as people said before me it would be better to use compareTo or compareToIgnoreCase method from String library. To make this work just change
isSmallerThan(value, array[index-1])
into
array[index-1].compareToIgnoreCase(value) > 0.
Using compareTo() method, implementation of insertion sort algorithm can look like this:
class InsertionSorter {
public String[] sortArrayOfStrings(String[] array) {
for (int i = 1; i < array.length; i++) {
String element = array[i];
int j;
for (j = i - 1; j >= 0 && element.compareTo(array[j]) <= 0; j--)
array[j + 1] = array[j];
array[j + 1] = element;
}
return array;
}
}
Example tests:
public class InsertionSorterTest {
#Test
public void shouldSortTwoLetterWords() {
String[] arr = {"zz", "bb", "cb", "ba", "za", "zb", "cz", "ab", "aa"};
String[] sortedArray = new InsertionSorter().sortArrayOfStrings(arr);
Assert.assertEquals(sortedArray, new String[]{"aa", "ab", "ba", "bb", "cb", "cz", "za", "zb", "zz"});
}
#Test
public void shouldSortLongerWords() {
String[] arr = {"bbz", "bba", "abz", "abc"};
String[] sortedArray = new InsertionSorter().sortArrayOfStrings(arr);
Assert.assertEquals(sortedArray, new String[]{"abc", "abz", "bba", "bbz"});
}
}

Java, combination algorithm with arrays

I am trying to implement an algorithm to calculate all combinations of an Array where one character is replaced by '*' without changing the order of the Arrays entries.
For example the following Array with two entries:
{"A", "B"}
Should reproduce this Output:
[A, B]
[*, B]
[A, *]
[*, *]
My current code is:
public class TestCombination {
public static void combinations(List<String[]> values, String[] attr, String all, int iteration) {
String[] val = new String[attr.length];
for (int i = 0; i < attr.length; i++) {
val[i] = attr[i];
}
if (iteration < attr.length) {
val[iteration] = all;
}
values.add(val);
iteration = iteration + 1;
if (Math.pow(attr.length, 2) != iteration) {
combinations(values, attr, all, iteration);
}
}
public static void main() {
String[] values = new String[] {"A", "B"};
List<String[]> resultValues = new ArrayList<String[]>();
combinations(resultValues, values, "*", 0);
for (String[] res : resultValues) {
System.out.println(Arrays.deepToString(res));
}
}
}
The Output i get is:
[*, B]
[A, *]
[A, B]
[A, B]
This is especially because of this not correct code:
if (iteration < attr.length) {
val[iteration] = all;
}
I do not have any idea, how the next possible index can be calculated to replace the Array value at that index by '*'.
Can you give me please some hints on that?
One simple approach is to use a bit mask of length n. Iterate all n-digit binary numbers, and then for each of the n positions do the following:
If position i has one, output an asterisk *
If position i has zero, output the original value.
This will cover all combinations.
String[] a = new String[] {"A", "B", "C"};
for (int mask = 0 ; mask != 1<<a.length ; mask++) {
for (int i = 0 ; i != a.length ; i++) {
if ((mask & 1<<i) != 0) {
System.out.print("* ");
} else {
System.out.print(a[i]+" ");
}
}
System.out.println();
}
Demo.
My solution is a modification of #dasblinkenlight solution where I'm using recursive function and not mask bit. My solution is in javascript.
var arr = ['A', 'B', 'C'],
len = arr.length,
pattern = function(startIndex, arr) {
var newArr = [].concat(arr),
i;
newArr[startIndex] = '*';
console.log(newArr.toString());
for (i = startIndex + 1; i < len; i++) {
pattern(i, newArr);
}
};
console.log(arr.toString())
for (i = 0; i < len; i++) {
pattern(i, arr);
}
You can use a recursive function to get the current string and one index and one time change the character at that index to * and another time call the function without changing the character at that index. Print the result when index reaches end of the string:
public class Main{
public static void main(String args[]){
f(new StringBuilder("ABC"),0);
}
public static void f(StringBuilder str, int index){
if (index == str.length()){
System.out.println(str);
return;
}
f(str, index+1);
char c = str.charAt(index);
str.setCharAt(index, '*');
f(str, index+1);
str.setCharAt(index, c);
}
}
output
ABC
AB*
A*C
A**
*BC
*B*
**C
***

no suitable method found for sort(int[],<anonymous Comparator<Integer>>)

Algorithm question: Given a list of non negative integers, arrange them such that they form the largest number.
For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330.
Note: The result may be very large, so you need to return a string instead of an integer.
public class Solution {
public String largestNumber(int[] num) {
Arrays.sort(num, new java.util.Comparator<Integer>() {
#Override
public int compare(Integer a, Integer b) {
String s1 = String.valueOf(a), s2 = String.valueOf(b);
return Integer.parseInt(s1 + s2) - Integer.parseInt(s2 + s1);
}
});
StringBuilder builder = new StringBuilder();
for (int i = num.length - 1; i >= 0; i--) builder.append(num[i]);
return builder.toString();
}
}
Result: Line 3: error: no suitable method found for sort(int[],<anonymous Comparator<Integer>>)
Does anyone know how to modify it? Thanks!
Thank you for all your detail answers, I have modified my code as
public String largestNumber(int[] num) {
int N = num.length;
String[] aux = new String[N];
for (int i = 0; i < N; i++) aux[i] = String.valueOf(num[i]); // int[] -> String[]
Arrays.sort(aux, new Comparator<String>() {
#Override
public int compare(String a, String b) {
return (int) (Long.parseLong(a + b) - Long.parseLong(b + a)); // note the overflow of int, max + max
}
});
StringBuilder builder = new StringBuilder();
for (int i = N - 1; i >= 0; i--) builder.append(aux[i]);
int sub = 0;
for ( ; sub < builder.length() - 1 && builder.charAt(sub) == '0'; sub++);
return builder.substring(sub).toString();
}
And I am still trying to find a way to avoid using extra space.
The reason for this is that int and Integer are different types. int is a primitive, and Integer is its object wrapper. Comparator<T> works only with objects; it does not work with primitives.
Put ints in a container of Integers, say, an ArrayList<Integer>, and use your comparator to solve the problem.
Note that your approach may fail for very large integers, because concatenating two valid ints may produce a number too large for an int to hold. You could return (s1+s2).compareTo(s2+s1) instead for lexicographical comparison, which is identical to numeric comparison for numbers of the same length.
You must use Integer
Integer[] nums = new Integer[]{3, 30, 34, 5, 9};
public class Solution {
public String largestNumber(Integer[] num) {
Arrays.sort(num, new java.util.Comparator<Integer>() {
#Override
public int compare(Integer a, Integer b) {
String s1 = String.valueOf(a), s2 = String.valueOf(b);
return Integer.parseInt(s1 + s2) - Integer.parseInt(s2 + s1);
}
});
StringBuilder builder = new StringBuilder();
for (int i = num.length - 1; i >= 0; i--) builder.append(num[i]);
return builder.toString();
}
}

Multiple sort algorithm (sorting within a sorted field) in Java

ArrayList data example:
BJM 300 AC4507 TOM_JONES, BDM 290 DC4058 ALAN_FIELD, ADG 350 BA3240 JON_THORN
I need to sort the ArrayList above into ascending sequence of the third column within the second column within the third column?
public static ArrayList sortLoad1(ArrayList<WorkLoad> loads){
String s1, s2;
WorkLoad temp; //Some local variables
for(int i = 0 ; i < loads.size(); i++){ //Loop forward
for(int j = loads.size()-1; j>i ;j--){ //Loop backward
s1 = loads.get(j-1).getDeptCode(); //Extract 1st
s2 = loads.get(j).getDeptCode(); //Extract 2nd
if(i+1<loads.size()&&s1.compareTo(s2)>-1){ //Compare them lexicographically
temp = loads.get(j-1);
//If s1 follows s2 then switch both
loads.set(j-1, loads.get(j));
loads.set(j, temp);
}//endif
}//end loop 2
}//end loop 1
return loads;
}
Above is the code I have ATM. This sorts the first column (BJM, BDM & ADG columns) but what would I have to do to sort within the sorted data as I mentioned above?? I thought sorting 3 times, but that's not going to work is it?
I've tried the nested sort (see below) mentioned below but no joy:
public static ArrayList sortLoad1(ArrayList<TeachingLoad> loads){
String s1, s2;
TeachingLoad temp; //Some local variables
for(int i = 0 ; i < loads.size(); i++){ //Loop throuth
for(int j = loads.size()-1; j>i ;j--){ //Loop through
s1 = loads.get(j-1).getLecturerID(); //Extract 1st
s2 = loads.get(j).getLecturerID(); //Extract 2nd
if(i+1<loads.size()&&s1.compareTo(s2)>-1){ //Compare them lexicographically
temp = loads.get(j-1);
//If s1 follows s2 then switch both
loads.set(j-1, loads.get(j));
loads.set(j, temp);
}
else{
for(int k = 0 ; k < loads.size(); k++){
for(int l = loads.size()-1; l>i ;l--){
s1 = loads.get(l-1).getDepartmentNumber();
s2 = loads.get(l).getDepartmentNumber();
if(k+1<loads.size()&&s1.compareTo(s2)>-1){
temp = loads.get(l-1);
loads.set(l-1, loads.get(l));
loads.set(l, temp);
}
else{
for(int m = 0 ; m < loads.size(); m++){
for(int n = loads.size()-1; n>i ;n--){
s1 = loads.get(n-1).getSchoolCode();
s2 = loads.get(n).getSchoolCode();
if(m+1<loads.size()&&s1.compareTo(s2)>-1){
temp = loads.get(n-1);
loads.set(n-1, loads.get(n));
loads.set(n, temp);
}
}
}
}
}
}
}
}//end loop 2
}//end loop 1
return loads;
}
You need to nest the sorts.
Essentially do the first comparison. If the result is not 0 then use that result.
If result is 0 then do the next comparison. Again if result is not 0 then use it.
You can continue this process for as many nested comparisons as you require.
The neatest way to implement it is as a custom comparator though. Then you can just do Collections.sort(list, comparitor) and it will efficiently and quickly sort the list using an appropriate algorithm for the list.
For example if you have:
class X {
int a, b, c;
}
Comparator<X> comparator = new Comparator<X>() {
public int compare(X one, X two) {
int result = one.a-two.a;
if (result == 0) {
result = one.b-two.b;
if (result == 0) {
result = one.c-two.c;
}
}
return result;
}
}
That will sort a list of X first by a, then by b, then by c.
To use it just do:
Collections.sort(list, comparator);

How to Find Union of Two String Arrays

I am trying to find the union of two string arrays. I have created a new array and have copied all the data from the first set into the new array. I am having trouble adding the information from the second set into the new array.
I need to use loops to search the second array and find the duplicates. I keep getting an ArrayIndexOutOfBoundsException.
Here is my current code:
static String[] union(String[] set1, String[] set2) {
String union[] = new String[set1.length + set2.length];
int i = 0;
int cnt = 0;
for (int n = 0; n < set1.length; n++) {
union[i] = set1[i];
i++;
cnt++;
}
for (int m = 0; m < set2.length; m++) {
for (int p = 0; p < union.length; p++) {
if (set2[m] != union[p]) {
union[i] = set2[m];
i++;
}
}
}
cnt++;
union = downSize(union, cnt);
return union;
}
The standard way of doing intersections or unions is using a set. You should use the Set class from collections framework.
Create two arraylist objects for your two arrays.
Define a Set object.
Add both the arraylist objects into the Set using addAll method.
As set holds unique elements, the set forms the union of
both arrays.
//push the arrays in the list.
List<String> list1 = new ArrayList<String>(Arrays.asList(stringArray1));
List<String> list2 = new ArrayList<String>(Arrays.asList(stringArray2));
HashSet <String> set = new HashSet <String>();
//add the lists in the set.
set.addAll(list1);
set.addAll(list2);
//convert it back to array.
String[] unionArray = set.toArray(new String[0]);
Using Set is going to be one of the easiest way:
public static String[] unionOf(String[] strArr1, String[] strArr2) {
Set<String> result = new HashSet<String>();
result.addAll(Arrays.asList(strArr1));
result.addAll(Arrays.asList(strArr2));
return result.toArray(new String[result.size()]);
}
There are also other utilities that can help in similar work, e.g. Guava:
public static String[] unionOf(String[] strArr1, String[] strArr2) {
return Sets.union(Sets.newHashSet(strArr1),
Sets.newHashSet(strArr2))
.toArray(new String[0]);
}
You have several problems with this part of your code:
for(int m = 0; m < set2.length; m++)
for(int p = 0; p < union.length; p++)
if(set2[m] != union[p])
{
union[i] = set2[m];
i++;
}
cnt++;
First, you should be using !equals() instead of != to compare strings. Second, despite the indenting, the statement cnt++ is not part of the outer loop. You don't need both i and cnt; their values should always match. Finally, you are adding set2[m] once for each element of union that is different from it. You only want to add it once. Here's a version that should work:
static String[] union( String[] set1, String[] set2 )
{
String union[] = new String[set1.length + set2.length];
System.arraycopy(set1, 0, union, 0, set1.length); // faster than a loop
int cnt = set1.length;
for(int m = 0; m < set2.length; m++) {
boolean found = false;
for(int p = 0; p < union.length && !found; p++) {
found = set2[m].equals(union[p]);
}
if(!found)
{
union[cnt] = set2[m];
cnt++;
}
}
union = downSize( union, cnt );
return union;
}
As other posters have noted, an alternative approach is to use a HashSet<String>, add the elements found in the two arrays, and turn the result back into an array.
You get ArrayIndexOutOfBoundsException on this line:
union[i] = set2[m];
because you keep increasing i somewhere around: set2.length * union.length times (nested loops).
Doing what R.J wrote will not give you the union - you'll have many duplicate items since by doing: set2[m].equals(union[p]) you compare every member of set2 to all the members of union and for each member that it's not equal to - you add it. so you end up adding the same items multiple times!
The right way to do it is like Deepak Mishra suggested by using Set which will "take care" of the duplicates.
Example:
int[] a = {1,2,3,4,5};
int[] b = {4,5,6,7};
Set union = new HashSet<Integer>();
for(int i=0; i<a.length; i++) union.add(a[i]);
for(int i=0; i<b.length; i++) union.add(b[i]);
Object[] ans = union.toArray();
for(int i=0; i<ans.length; i++)
System.out.print(ans[i]+" ");
will output:
1 2 3 4 5 6 7
Since it's HW I won't write the code for the answer, but I'll give you a tip: doing it your way requires O(n^2) - if you'll think a bit I'm sure that you can find a way to do it in a better time, say, O(n log n)...
Though using the SETS is the best solution, here is a simple solution.
private static String getUnion(String a, String b, boolean ignoreCase) {
String union = "";
if (a == null || b == null || a.length() < 1 || b.length() < 1) {
return union;
}
char[] shortest;
char[] longest;
if (ignoreCase) {
shortest = (a.length() <= b.length() ? a : b).toLowerCase().toCharArray();
longest = (a.length() <= b.length() ? b : a).toLowerCase().toCharArray();
} else {
shortest = (a.length() <= b.length() ? a : b).toLowerCase().toCharArray();
longest = (a.length() <= b.length() ? b : a).toLowerCase().toCharArray();
}
StringBuilder sb = new StringBuilder();
for (char c : shortest) {
for (int i = 0; i < longest.length; i++) {
if (longest[i] == c) {
sb.append(c);
}
}
}
union = sb.toString();
return union;
}
and following are few tests.
public static void main(String[] args) {
System.out.println("Union of '' and BXYZA is " + getUnion("", "BXYZA", true));
System.out.println("Union of null and BXYZA is " + getUnion(null, "BXYZA", true));
System.out.println("Union of ABC and BXYZA is " + getUnion("ABC", "BXYZA", true));
System.out.println("Union of ABC and BXYZA is " + getUnion("ABC", "bXYZA", false));
}

Categories