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));
}
Related
I'm new at programming. I have to write a code, main requirements - user chooses the sorting method (one is already added, the second one I will add later), enters the amount of elements in the array, enters the elements and then the code sorts them. But it looks like the code only takes the last entered element and tries to sort it. What do I have to do to make it sort all entered elements?
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("181RDB094 Līva Gundega Ermansone 1");
System.out.print("method:");
int M;
if (sc.hasNextInt())
M = sc.nextInt();
else {
System.out.println("input-output error");
sc.close();
return;
}
System.out.print("count:");
int count = sc.nextInt();
int[] masīvs = new int[count];
System.out.println("items:");
masīvs = new int[count];
for (int i = 0; i < count; i++) {
masīvs[i] = sc.nextInt();
}
System.out.println("result:");
if (M == 1) {
int[] b = new int[count];
int[] less = new int[count];
int[] equal = new int[count];
int k;
for (int i = 0; i < count; i++)
for (int j = 0; j < count; j++) {
if (masīvs[i] == masīvs[j]) {
equal[i] = i++;
} else if (masīvs[i] > masīvs[j]) {
less[i] = i++;
}
}
for (int i = 0; i < count; i++) {
k = less[i];
for (int j = 0; j < equal[i]; j++) {
b[k + j] = masīvs[i];
}
}
for (int i = 0; i < count; i++) {
masīvs[i] = b[i];
System.out.print(masīvs[i] + " ");
}
} else if (M == 2) {
} else {
System.out.println("input-output error");
return;
}
}
Sorry for the ugly code, it's just a draft.
Expected:
181RDB094 Līva Gundega Ermansone 1
method:1
count:4
items:
13
31
55
2
result:
55 31 13 2
Actual results:
181RDB094 Līva Gundega Ermansone 1
method:1
count:4
items:
13
31
55
2
result:
2 2 2 0
You can add a simple for loop after filling your array to check the contents. There, you can see that all entries are written into the array correctly.
This will output:
Array:13
Array:31
Array:55
Array:2
for (int i = 0; i < masīvs.length; i++) {
System.out.println("Array:" + masīvs[i]);
}
The sorting method you are following fixes a set of equal elements at their proper position by finding the no of elements less than those elements.
The problem in sorting lies in finding the no of elements less and equal to.
equal[i]++; instead of equal[i]=i++;
Similarly,
less[i]++; instead of less[i]=i++;
If you're using Java 8 or more recent, you may be able to use the ArrayList class (with the Integer class) instead of an 1D array (i.e. int[] var = new int[x]); it would allow you to use its sort(Comparator) method instead.
You would have to create a Comparator instance (lambda function, or anonymous) or an implementing class, unless you want to use the natural ordering of those.
It would give you something around those two lines:
ArrayList<Integer> var = new ArrayList<>();
and var.sort(); (assuming you use the natural ordering)
It might however be harder to manipulate at first, if you're new to the Java Collection Framework, so don't hesitate to ask questions.
P.S.: I might have misunderstood the code, so just tell me so I can fix my answer.
P.S.S.: Somewhat unrelated, and it's probably in your mind (ignore that part then), but I would recommend you to refactor that into much more smaller methods/functions.
I think that your code organization is very bad. It's easier to give you more correct solution, than count and fix your problem:
public class Foo {
public static void main(String... args) {
final BiFunction<int[], Comparator<Integer>, int[]> sort =
(items, comparator) -> Arrays.stream(items)
.boxed()
.sorted(comparator)
.mapToInt(i -> i)
.toArray();
try (Scanner scan = new Scanner(System.in)) {
Comparator<Integer> comparator = getSortingMethod(scan);
int[] items = getItems(scan);
int[] sorted = sort.apply(items, comparator);
System.out.println(Arrays.toString(sorted));
}
}
private static final Comparator<Integer> SORT_ASC = Comparator.naturalOrder();
private static final Comparator<Integer> SORT_DESC = Comparator.reverseOrder();
private static final Comparator<Integer> SORT_NULL = (one, two) -> {
throw new IllegalArgumentException("input-output error");
};
private static Comparator<Integer> getSortingMethod(Scanner scan) {
System.out.println("181RDB094 Līva Gundega Ermansone 1");
System.out.print("method:");
try {
int M = scan.nextInt();
if (M == 1)
return SORT_DESC;
if (M == 2)
return SORT_ASC;
return SORT_NULL;
} catch(RuntimeException e) {
return SORT_NULL;
}
}
private static int[] getItems(Scanner scan) {
System.out.print("count:");
int[] items = new int[scan.nextInt()];
System.out.println("items:");
for (int i = 0; i < items.length; i++)
items[i] = scan.nextInt();
return items;
}
}
okay so we basically have this question to answer, but I am very confused and don't know how to use recursion to get all possible combinations.. Please someone save me!
Write a public static method threadings, which takes an int n (representing the number of beads on each necklace) and a Set of Strings (representing the available bead colours; your code must not alter this Set),and returns a Set of ArrayLists of Strings, representing all the orders in which n beads of the given colours can be threaded. If n < 1, return a Set containing just one, empty, ArrayList.
Examples of correct behaviour:
• threadings(0, {red,green}) = {[]}
• threadings(1, {red,green}) = {[red],[green]}
• threadings(2, {red,green})
= {[red,red],[red,green],[green,red],[green,green]}
• threadings(3, {red}) = {[red,red,red]}
Hint: you will probably want threadings to call itself recursively, although
full marks are available for any correct method.
This is what I have written until now:
public static HashSet<ArrayList<String>> threadings (int n, Set<String> colours){
HashSet<ArrayList<String>> result= new HashSet<ArrayList<String>>();
ArrayList<String> inresult= new ArrayList<String>();
String[] col= new String[colours.size()];
if (n==0){
result.add(inresult);
return result;
}else{
}
}
Try this:
public static HashSet<ArrayList<String>> threadings (int n, Set<String> colours) {
List<String> colorsList = new ArrayList<>(colours);
ArrayList<String> resultList = new ArrayList<>();
HashSet<ArrayList<String>> result = new HashSet<ArrayList<String>>();
int carry;
int[] indices = new int[n];
do
{
for(int index : indices) {
resultList.add(colorsList.get(index));
}
result.add(resultList);
resultList = new ArrayList<>();
carry = 1;
for(int i = indices.length - 1; i >= 0; i--)
{
if(carry == 0)
break;
indices[i] += carry;
carry = 0;
if(indices[i] == colorsList.size())
{
carry = 1;
indices[i] = 0;
}
}
}
while(carry != 1);
return result;
}
I have a list of lists:
List<List<String>> someList = new List<List<>>();
The maximum size of a list is five strings. It's something like below:
someList.get(0).size(); // 4 elements
someList.get(1).size(); // 1 elements
someList.get(2).size(); // 3 elements
someList.get(3).size(); // 1 elements
...
I'm trying to devise a method to create a new list of a specific size (1-5 elements) by combining some of the above nested lists. I could do something like the below (in this example, three elements):
public List<String> getThree() {
for (int j = 0; j < someList.size(); j++) {
//look for nested lists of size 3
if (someList.get(j).size() == 3) {
return someList.get(j);
}
for (int j = 0; j < someList.size(); j++) {
//if found nested list of size 2, find one of size 1 to combine
if (someList.get(j).size() == 2) {
for (int k = 0; k < someList.size(); k++) {
if (someList.get(k).size() == 1) {
return someList.get(j).add(someList.get(k).get(0));
}
}
}
for (int j = 0; j < someList.size(); j++) {
//if found nested list of size 1, find one of size 2 to combine
if (someList.get(j).size() == 1) {
for (int l = 0; l < someList.size(); l++) {
if (someList.get(l).size() == 2) {
return someList.get(j).addAll(someList.get(l));
}
}
}
}
}
I haven't included the loop for if no sublists are of size 2, to find three of size 1, but you can imagine how long and how ugly it can get. The order is important, thus the for loops incrementing sequentially (ie. I'd rather combine subList 1 + 2 more than 2 + 3, 1 + 3 more than 2 + 3, etc).
I'm hoping to find a way to dynamically implement this. I can only fathom how unreadable and long the getFive method will be provided my current methodology. I have multiple methods (getOne through getFive), it doesn't need to be dynamic in this sense, I'd just like to get rid of a lot of the if/else and for loops to reduce complexity and improve readability.
I should mention this is homework related, so I don't quite want a specific answer, but a nudge in the right direction. Something modulo perhaps? To do with remainders?
edit; to clarify and give an example:
aList = new List<String>;
aList.add("a");
aList.add("b");
someList.add(aList);
bList = new List<String>;
bList.add("c");
someList.add(bList);
newList = someList.getThree();
//newList.size() == 3
//newList contains "a","b","c"
The getThree() method is creating a new list comprised of elements from the sublists of someList. It cannot split a sublist (ie. it can't take 1 element from a sublist of 2 elements), it's combining whole sublists.
If your intention is to keep collecting from successive lists until you get 5 elements, keep adding then break out when your list is full:
public static List<String> fill(List<List<String>> sources, int size) {
List<String> list = new ArrayList<>();
for (List<String> source : sources)
if (source.size() <= size - list.size())
list.addAll(source);
return list;
}
If you want to consume the largest lists first, add this line as the first line of the method:
Collections.sort(sources, (a, b) -> b.size() - a.size());
In java 8, quite succinct:
public static List<String> fill(List<List<String>> sources, int size) {
return sources.stream().reduce(new ArrayList<>(),
(a, b) -> {if (b.size() <= a.size() - size) a.addAll(b); return a;});
}
and with the largest-first mod:
public static List<String> fill(List<List<String>> sources, int size) {
return sources.stream()
.sorted((a,b) -> b.size() - a.size())
.reduce(new ArrayList<>(), (a, b) ->
{if (b.size() <= a.size() - size) a.addAll(b); return a;});
}
Since you state that the priority of combining Lists is from left to right. An O(N^2) loop is sufficient to handle combining sublists to be less than or equal to your desired amount.
public static void main(String[] args) throws Exception {
List<List<String>> someList = new ArrayList() {{
add(new ArrayList() {{
add("a1");
add("a2");
}});
add(new ArrayList() {{
add("b1");
}});
add(new ArrayList() {{
add("c1");
add("c2");
add("c3");
}});
add(new ArrayList() {{
add("d1");
}});
}};
combine(someList, 4);
for(List<String> subList : someList) {
System.out.println(subList);
}
}
private static void combine(List<List<String>> someList, int combineAmount) {
for (int i = 0; i < someList.size(); i++) {
// Check if the current list already equals or exceeds the combineAmount
if (someList.get(i).size() >= combineAmount) {
continue;
}
// Add sublists to the current sublists until the size of the current
// sublist equals or exceeds the combineAmount
for (int j = i + 1; j < someList.size(); j++) {
if (someList.get(i).size() + someList.get(j).size() > combineAmount) {
continue;
}
someList.get(i).addAll(someList.get(j));
someList.remove(j);
j--;
// Don't bother checking other sublists if the newly
// combined sublists equals or exceeds the combineAmount
if (someList.get(i).size() >= combineAmount) {
break;
}
}
}
}
Results (combineAmount = 4):
[a1, a2, b1, d1]
[c1, c2, c3]
Results (combineAmount = 2):
[a1, a2]
[b1, d1]
[c1, c2, c3]
Results (combineAmount = 6):
[a1, a2, b1, c1, c2, c3]
[d1]
From what I understand you want to combine a list of lists into a total of 5 indexes. When doing this you want it to prioritize the left side first.
Here is a method I have created to do this. I know you did not want a specific example, but I think an example will help you understand as well as help others who also have this question:
private static List<String> getListOf(List<List<String>> someList, int size) {
List<List<String>> combine = new ArrayList<List<String>>();
List<List<String>> combinePrev = new ArrayList<List<String>>();
int value = 0;
int indexCloseValue = 0;
int indexClose;
for(int i = 0; i < someList.size(); i++){//Loops through the lists
value = someList.get(i).size();
boolean[] indexAdded = new boolean[someList.size()];//Used to make sure to not add duplicates
indexAdded[i] = true;
combine.add(someList.get(i));//add current loop to the combine list.
do{//A loop to try to add values other than the one of index i to equal size. This loops multiple times because it may take more than two to equal size.
indexCloseValue = 0;
indexClose = -1;
for(int j = 0; j < someList.size(); j++){
if(!indexAdded[j]){
int listSize = someList.get(j).size();
if(value + listSize > indexCloseValue && value + listSize <= size){
indexCloseValue = listSize;
indexClose = j;
}
}
}
if(indexClose == -1){
break;
}else{
combine.add(someList.get(indexClose));
value+=indexCloseValue;
indexAdded[indexClose] = true;
}
}while(value + indexCloseValue < size);
int added = 0;
for(List<String> str : combine){//Check size of combine list
added+=str.size();
}
int addedPrev = 0;
for(List<String> str : combinePrev){//Check size of combinePrev list
addedPrev+=str.size();
}
if(added > addedPrev && added <= size){
combinePrev = new ArrayList<List<String>>(combine);//Set combinePrev to combine if it is larger but less than size
}
combine = new ArrayList<List<String>>();//Reset combine
}
List<String> returnList = new ArrayList<String>();
for(List<String> list : combinePrev){//converts double list to a single list of strings at length "size".
for(String str : list){
returnList.add(str);
}
}
return returnList;
}
If there are any problems with this code or you have a question ask me in the comments.
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);
I have array of ValueA and ValueB(int type) . I am reading each value from array using a for loop.
I want to concatenate all there values in a single String. these value should be in the form of like these
ValueA1":"valueB1"|"ValueA2":"valueB2"|"ValueA3":"valueB3"|"ValueA4":"valueB4"|"....
I want this in Java, please can some ne help me with code..
You could try something like this
int[] valueA = methodWhichFillsA();
int[] valueB = methodWhichFillsB();
StringBuilder sb = new StringBuilder();
int maxSize = Math.max(valueA.length, valueB.length);
for(int i = 0; i < maxSize; i++){
if(i > 0)
sb.append("|");
if(i < valueA.length)
sb.append(valueA[i]);
sb.append(":");
if(i < valueB.length)
sb.append(valueB[i]);
}
System.out.println(sb.toString());
This will evaluate the size of the biggest array between valueA and valueB, loop on this size. If the element exists it's printed.
The first if is used to add the separator, if it's the first iteration no need for a "|"
Assuming the arrays are of different size, this solution will zip them together up until the end of the shorter array:
StringBuilder sb = new StringBuilder();
for(int i = 0; i < Math.min(arr1.length, arr2.length); i++){
sb.append( arr1[i] ).append("\":\"").append( arr2[i] ).append("\"|\"");
}
System.out.println(sb.toString());
Just a different way of doing it, this uses Guava
private String test(int[] a, int[] b) {
List<Integer> al = Lists.newArrayList();
List<Integer> bl = Lists.newArrayList();
for (Integer ai : a) {
al.add(ai);
}
for (Integer bi : b) {
bl.add(bi);
}
List<String> sets = Lists.newArrayList();
Iterator<Integer> itera = al.iterator();
Iterator<Integer> iterb = bl.iterator();
while(itera.hasNext() && iterb.hasNext()) {
sets.add(itera.next()+":"+iterb.next());
}
return Joiner.on("|").join(sets);
}
I was surprised to find no primitive array to list methods. If you can think of an elegant way to do that besides pulling it out into another method, the this code could be made cleaner.