Split a List of Strings based on value in Java - java

What I want to do is to split an array of strings, when the first 6 characters in the string are zeroes ("000000") or when all the digits in the string are zeroes. Limiting to 6 characters won't be very dynamic.
I got this code, and it does what I want to achieve.
import java.util.*;
public class Main
{
public static void main(String[] args) {
ArrayList<String> unsplitted = new ArrayList<String>();
unsplitted.add("000000: this_should_go_into_first_array");
unsplitted.add("000234: something1");
unsplitted.add("0000ff: something2");
unsplitted.add("000111: something3");
unsplitted.add("000051: something4");
unsplitted.add("007543: something5");
unsplitted.add("000000: and_this_should_go_into_second_array");
unsplitted.add("005612: something7");
unsplitted.add("005712: something8");
System.out.println("Unsplitted list: "+ unsplitted);
List<String> arrlist1 = unsplitted.subList(0, 6);
List<String> arrlist2 = unsplitted.subList(6, unsplitted.size());
System.out.println("Sublist of arrlist1: "+ arrlist1);
System.out.println("Sublist of arrlist2: "+ arrlist2);
}
}
Which prints out the wanted results
Sublist of arrlist1: [000000: this_should_go_into_first_array, 000234: something1, 0000ff: something2, 000111: something3, 000051: something4, 007543: somethi
ng5]
Sublist of arrlist2: [000000: and_this_should_go_into_second_array, 005612: something7, 005712: something8]
However, I don't know the indexes for the zeroes beforehand, so how can I achieve the same result by finding the zeroes dynamically?

You can simply iterate in your array and create "bucket" each time you detect your 000000 string :
ArrayList<String> unsplitted = new ArrayList<String>();
unsplitted.add("000000: this_should_go_into_first_array");
unsplitted.add("000234: something1");
unsplitted.add("0000ff: something2");
unsplitted.add("000111: something3");
unsplitted.add("000051: something4");
unsplitted.add("007543: something5");
unsplitted.add("000000: and_this_should_go_into_second_array");
unsplitted.add("005612: something7");
unsplitted.add("005712: something8");
List<List<String>> results = new ArrayList<>();
unsplitted.forEach(w -> {
if(w.startsWith("000000") || results.isEmpty()) {
// no bucket or detect 000000
List<String> bucket = new ArrayList<>();
bucket.add(w);
results.add(bucket);
}
else {
// not contains 00000 put the value in the last bucket
results.get(results.size() - 1).add(w);
}
});
results.forEach(w -> {
System.out.println("Sublist " + w);
});
Is it the result that you expected ?
The result :
Sublist [000000: this_should_go_into_first_array, 000234: something1, 0000ff: something2, 000111: something3, 000051: something4, 007543: something5]
Sublist [000000: and_this_should_go_into_second_array, 005612: something7, 005712: something8]

The question is quite interesting. There are different way to implement this, but I am going to show you a solution where it can be applied with any length of the first part, which we can consider as a key.
As you said in your introduction, it wouldn't be dynamic if the check was limited to only 6 characters. Based on this, as an example, you can take the position of the character ':' as reference and apply a partitioning among the elements of the array.
Here is the solution I propose:
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class Main
{
public static void main(String[] args) {
ArrayList<String> unsplitted = new ArrayList<String>();
unsplitted.add("000000: this_should_go_into_first_array");
unsplitted.add("000234: something1");
unsplitted.add("0000ff: something2");
unsplitted.add("000111: something3");
unsplitted.add("000051: something4");
unsplitted.add("007543: something5");
unsplitted.add("000000: and_this_should_go_into_second_array");
unsplitted.add("005612: something7");
unsplitted.add("005712: something8");
System.out.println("Non-split list: "+ unsplitted);
Predicate<String> filter = (String s) -> {
int indexOfCol = s.indexOf(":");
return s.substring(0, indexOfCol).equals("0".repeat(indexOfCol));
};
Map<Boolean, List<String>> splitMap = unsplitted.stream()
.collect(Collectors.partitioningBy(filter));
List<String> arrayZeroStart = splitMap.get(true);
List<String> arrayNonZeroStart = splitMap.get(false);
System.out.println("Sublist of arrayZeroStart: "+ arrayZeroStart);
System.out.println("Sublist of arrayWithout: "+ arrayNonZeroStart);
}
}
And here is the output:
Non-split list: [000000: this_should_go_into_first_array, 000234: something1, 0000ff:
something2, 000111: something3, 000051: something4, 007543: something5, 000000: and_this_should_go_into_second_array, 005612: something7, 005712: something8]
Sublist of arrayZeroStart: [000000: this_should_go_into_first_array, 000000: and_this_should_go_into_second_array]
Sublist of arrayWithout: [000234: something1, 0000ff: something2, 000111: something3, 000051: something4, 007543: something5, 005612: something7, 005712: something8]

Related

How to add strings into an arraylist between two strings

I am trying to figure out how to add a string, into a string ArrayList, between two strings that are already in. So if I have this
ArrayList<String> List = new ArrayList<String>();
List.add("Yes");
List.add("No");
List.add("Maybe");
How would I go along putting the word "Or" between them and make the ArrayList contain
"Yes" "Or" "No" "Or" "Maybe"?
I have three advices.
First, to name the variables, start with lower-case.
Second, use List as type of variable, instead of ArrayList, you will thank me later, trust me.
Third, to do what you ask for, there is overloaded method add for choosing position :
List<String> list = new ArrayList<String>();
list.add("Yes");
list.add("No");
list.add(1,"Maybe"); //insert into position 1 and shift everything to the right.
For this example, if you use System.out.println(list);, you will get this output :
[Yes, Maybe, No]
For adding Or instruction, it would be like this :
List<String> list = new ArrayList<String>();
list.add("Yes");
list.add("No");
list.add("Maybe");
list.add(1, "Or");
list.add(3, "Or");
System.out.println(list);
Output :
[Yes, Or, No, Or, Maybe]
Also, if you want to make your program more re-usable, you can write a method, that will do this for you for any case of list :
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Yes");
list.add("No");
list.add("Maybe");
list.add("Probably");
list.add("Never");
List<String> orList = addOr(list);
System.out.println(orList);
}
public static List<String> addOr(List<String> list){
List<String> newList = new ArrayList<>();
int count = 0;
for(String text : list){
count++;
newList.add(text);
if (count != list.size()){
newList.add("Or");
}
}
return newList;
}
Having this output :
[Yes, Or, No, Or, Maybe, Or, Probably, Or, Never]
However, if you want to use that list for outputing some message for user, it is not good idea to add "Or", because it is really not part of information. Rather it is good, to create method, which will create output String you desire.
This code
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Yes");
list.add("No");
list.add("Maybe");
list.add("Probably");
list.add("Never");
String niceOutput = addOr(list);
System.out.println("Choose from following options: " + niceOutput);
}
public static String addOr(List<String> list){
String orText = "";
int count = 0;
for(String text : list){
count++;
orText += '\'' + text + '\'';
if (count != list.size()){
orText += " or ";
}
}
return orText;
}
Having this output :
Choose from following options: 'Yes' or 'No' or 'Maybe' or 'Probably' or 'Never'
According to Add object to ArrayList at specified index
List.add(1, "or")
List.add(3, "or")
This should solve your problem.

Java Generating Strings Recursively - All 1s then 1 and 0

Hey guys I'm trying to get the concept of recursion down by making a program that generates String of an ArrayList recursively. My basic algorithm is:
public static ArrayList<String> generateListOfAll1sStrings(int maxBits)
terminal condition: if maxBits is 1, return the simplest case: a list containing just "1"
otherwise:
recursively call generateListOfAll1sStrings() for the next-smallest bit-length, saving the list that is returned
find the longest string in that list and create a new string with "1" appended to it (making the next-longest string)
return a new list that contains all the elements of the shorter list along with the new string just added.
The code I have so far is:
package bincomb.model;
import java.util.ArrayList;
public class BinaryCombinationGenerator {
public static ArrayList<String> generateListOfAll1sStrings(int maxBits) {
String string = null;
ArrayList<String> listofJust1 = new ArrayList<String>();
ArrayList<String> otherArray = new ArrayList<String>();
int i = 1;
if (maxBits == 1) {
listofJust1.add("1");
return listofJust1;
}
if (maxBits > 1) {
for (String string2 : listofJust1) {
String comp = "";
if (!(comp.equals(string2))) {
comp = string2;
}
string = comp;
}
listofJust1.add(i, (string + "1"));
i++;
listofJust1 = BinaryCombinationGenerator.generateListOfAll1sStrings((maxBits-1));
System.out.println(listofJust1);
return listofJust1;
}
return listofJust1;
}
public static void main(String[] args) {
generateListOfAll1sStrings(10);
}
}
However, currently, I'm returning an IndexOutOfBoundsException. I think my for loop is causing the problem, but I'm not certain how to go about fixing it.
You're getting an java.lang.IndexOutOfBoundsException at this line listofJust1.add(i, (string + "1"));.
This is because the method list.add(index, objects) tries to add the object at index "1" but your array has 0 elements.
Either change it to listofJust1.add(i-1, (string + "1")); or simply listofJust1.add((string + "1"));
#Edit: here:
listofJust1.add(i, (string + "1"));
You want to add the string for the current (N) level of recursion but below you substitute this array with:
listofJust1 = BinaryCombinationGenerator.generateListOfAll1sStrings((maxBits-1));
Which basically says "get the result for (maxBits-1) and replace with it listofJust1" therefore you are losing what you added before.
Instead you should first get the list for level N-1 and then add the string for the current level:
listofJust1 = BinaryCombinationGenerator.generateListOfAll1sStrings((maxBits-1));
listofJust1.add(stringForThisLevel);
Also you need to rething how you are computing "string" at level N, doesn't seem right.

How to Count Unique Values in an ArrayList?

I have to count the number of unique words from a text document using Java. First I had to get rid of the punctuation in all of the words. I used the Scanner class to scan each word in the document and put in an String ArrayList.
So, the next step is where I'm having the problem! How do I create a method that can count the number of unique Strings in the array?
For example, if the array contains apple, bob, apple, jim, bob; the number of unique values in this array is 3.
public countWords() {
try {
Scanner scan = new Scanner(in);
while (scan.hasNext()) {
String words = scan.next();
if (words.contains(".")) {
words.replace(".", "");
}
if (words.contains("!")) {
words.replace("!", "");
}
if (words.contains(":")) {
words.replace(":", "");
}
if (words.contains(",")) {
words.replace(",", "");
}
if (words.contains("'")) {
words.replace("?", "");
}
if (words.contains("-")) {
words.replace("-", "");
}
if (words.contains("‘")) {
words.replace("‘", "");
}
wordStore.add(words.toLowerCase());
}
} catch (FileNotFoundException e) {
System.out.println("File Not Found");
}
System.out.println("The total number of words is: " + wordStore.size());
}
Are you allowed to use Set? If so, you HashSet may solve your problem. HashSet doesn't accept duplicates.
HashSet noDupSet = new HashSet();
noDupSet.add(yourString);
noDupSet.size();
size() method returns number of unique words.
If you have to really use ArrayList only, then one way to achieve may be,
1) Create a temp ArrayList
2) Iterate original list and retrieve element
3) If tempArrayList doesn't contain element, add element to tempArrayList
Starting from Java 8 you can use Stream:
After you add the elements in your ArrayList:
long n = wordStore.stream().distinct().count();
It converts your ArrayList to a stream and then it counts only the distinct elements.
I would advice to use HashSet. This automatically filters the duplicate when calling add method.
Although I believe a set is the easiest solution, you can still use your original solution and just add an if statement to check if value already exists in the list before you do your add.
if( !wordstore.contains( words.toLowerCase() )
wordStore.add(words.toLowerCase());
Then the number of words in your list is the total number of unique words (ie: wordStore.size() )
This general purpose solution takes advantage of the fact that the Set abstract data type does not allow duplicates. The Set.add() method is specifically useful in that it returns a boolean flag indicating the success of the 'add' operation. A HashMap is used to track the occurrence of each original element. This algorithm can be adapted for variations of this type of problem. This solution produces O(n) performance..
public static void main(String args[])
{
String[] strArray = {"abc", "def", "mno", "xyz", "pqr", "xyz", "def"};
System.out.printf("RAW: %s ; PROCESSED: %s \n",Arrays.toString(strArray), duplicates(strArray).toString());
}
public static HashMap<String, Integer> duplicates(String arr[])
{
HashSet<String> distinctKeySet = new HashSet<String>();
HashMap<String, Integer> keyCountMap = new HashMap<String, Integer>();
for(int i = 0; i < arr.length; i++)
{
if(distinctKeySet.add(arr[i]))
keyCountMap.put(arr[i], 1); // unique value or first occurrence
else
keyCountMap.put(arr[i], (Integer)(keyCountMap.get(arr[i])) + 1);
}
return keyCountMap;
}
RESULTS:
RAW: [abc, def, mno, xyz, pqr, xyz, def] ; PROCESSED: {pqr=1, abc=1, def=2, xyz=2, mno=1}
You can create a HashTable or HashMap as well. Keys would be your input strings and Value would be the number of times that string occurs in your input array. O(N) time and space.
Solution 2:
Sort the input list.
Similar strings would be next to each other.
Compare list(i) to list(i+1) and count the number of duplicates.
In shorthand way you can do it as follows...
ArrayList<String> duplicateList = new ArrayList<String>();
duplicateList.add("one");
duplicateList.add("two");
duplicateList.add("one");
duplicateList.add("three");
System.out.println(duplicateList); // prints [one, two, one, three]
HashSet<String> uniqueSet = new HashSet<String>();
uniqueSet.addAll(duplicateList);
System.out.println(uniqueSet); // prints [two, one, three]
duplicateList.clear();
System.out.println(duplicateList);// prints []
duplicateList.addAll(uniqueSet);
System.out.println(duplicateList);// prints [two, one, three]
public class UniqueinArrayList {
public static void main(String[] args) {
StringBuffer sb=new StringBuffer();
List al=new ArrayList();
al.add("Stack");
al.add("Stack");
al.add("over");
al.add("over");
al.add("flow");
al.add("flow");
System.out.println(al);
Set s=new LinkedHashSet(al);
System.out.println(s);
Iterator itr=s.iterator();
while(itr.hasNext()){
sb.append(itr.next()+" ");
}
System.out.println(sb.toString().trim());
}
}
3 distinct possible solutions:
Use HashSet as suggested above.
Create a temporary ArrayList and store only unique element like below:
public static int getUniqueElement(List<String> data) {
List<String> newList = new ArrayList<>();
for (String eachWord : data)
if (!newList.contains(eachWord))
newList.add(eachWord);
return newList.size();
}
Java 8 solution
long count = data.stream().distinct().count();

help with java hash map

can some one please explain what is happening in the code below and how it ends up with 36?
thanks
edit by Amir Rachum
public class HashMap2009 {
public static void main (String[] args) {
Map<String, Integer> myMap2009 =
new HashMap<String, Integer>();
myMap2009.put("one", new Integer(1));
myMap2009.put("three", new Integer(3));
myMap2009.put("five", new Integer(5));
myMap2009.put("seven", new Integer(7));
myMap2009.put("nine", new Integer(9));
System.out.println(oddOne(myMap2009));
}
private static int oddOne(Map<String, Integer> myMap2009) {
if (myMap2009.isEmpty())
return 11;
else {
Set<String> st = myMap2009.keySet();
String key = st.iterator().next();
int num = myMap2009.get(key);
myMap2009.remove(key);
return num + oddOne(myMap2009);
}
}
}
This is a simple example of recursion, which results in adding up all the keys in the map one by one and when the map is empty, it adds another 11. This sums up to 36.
That's a recursive function, that each time it is called, add the value of the first element in the map and then remove it.
If the map is empty it return 11
So: 9+7+5+3+1+11 = 36 ( 9,7,5,3,1 for each value in the map and 11 for when it is empty )
BTW, this looks to me as a terrible way to teach recursion ( because the map creates too much noise )
A simpler ( and I think more effective ) way would've been:
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
public class ArrayList2009 {
public static void main( String [] args ) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(3);
list.add(5);
list.add(7);
list.add(9);
System.out.println( addOne( list ) );
}
private static int addOne( List<Integer> list ){
if ( list.isEmpty() ) {
return 11;
} else {
Iterator<Integer> i = list.iterator();
int num = i.next();
i.remove();
return num + addOne( list );
}
}
}
Which does exactly the same, but introduce less noise because the List interface easier to understand.
When calling oddOne it will get
the first number
remove the number
add it to the result of oddOne (with the number removed)
this repeats till empty whne oddOne return 11
so we end up with
1 + (3 + (5 + (7 + (9 + 11)))) = 36
actually the order will e all jumbled up as it is a hashmap but this has no influence on adding numbers
You're making recursive calls, removing one element from the map per call.
You could start out with num == 1 (a map is unordered) and you remove this from your map. Then you do the recursive call, which gives you num == 3. This continues until your map is empty, which results in 1 + 3 + 5 + 7 + 9, and an additional 11 for your empty map.
Take a look at recursion: http://en.wikipedia.org/wiki/Recursion

Sorting an ArrayList<String> in a TreeMap

I am piping in a file. I am tracking word pairs from the file. Using a treemap the keys are all sorted. However, when i add words to those keys they are not sorted.
here is the part i need help on in the process function:
private static void process(){
if(!result.containsKey(thisWord)){
result.put(thisWord, new ArrayList<String>());
}
// Add nextWord to the list of adjacent words to thisWord:
result.get(thisWord).add(nextWord); // nextword is not sorted within the key
thisword is sorted
nextWord is not..
Can i use Collections.sort(result); somehow?
im just not sure how i get to the nextWord within the result to do that.
or, is there no way to do it within my situation. I would rather not change things unless you recommend it.
This is the program
import java.util.Map.Entry;
import java.util.TreeSet;
import java.io.*;
import java.util.*;
public class program1 {
private static List<String> inputWords = new ArrayList<String>();
private static Map<String, List<String>> result = new TreeMap<String, List<String>>();
public static void main(String[] args) {
collectInput();
process();
generateOutput();
}
private static void collectInput(){
Scanner sc = new Scanner(System.in);
String word;
while (sc.hasNext()) { // is there another word?
word = sc.next(); // get next word
if (word.equals("---"))
{
break;
}
inputWords.add(word);
}
}
private static void process(){
// Iterate through every word in our input list
for(int i = 0; i < inputWords.size() - 1; i++){
// Create references to this word and next word:
String thisWord = inputWords.get(i);
String nextWord = inputWords.get(i+1);
// If this word is not in the result Map yet,
// then add it and create a new empy list for it.
if(!result.containsKey(thisWord)){
result.put(thisWord, new ArrayList<String>());
}
// Add nextWord to the list of adjacent words to thisWord:
result.get(thisWord).add(nextWord); // need to sort nextword
// Collections.sort(result);
}
}
private static void generateOutput()
{
for(Entry e : result.entrySet()){
System.out.println(e.getKey() + ":");
// Count the number of unique instances in the list:
Map<String, Integer> count = new HashMap<String, Integer>();
List<String> words = (List)e.getValue();
for(String s : words){
if(!count.containsKey(s)){
count.put(s, 1);
}
else{
count.put(s, count.get(s) + 1);
}
}
// Print the occurances of following symbols:
for(Entry f : count.entrySet()){
System.out.println(" " + f.getKey() + ", " + f.getValue() );
}
}
System.out.println();
}
}
If you want the collection of "nextword"s sorted, why not use a TreeSet rather than an ArrayList? The only reason I can see against it is if you might have duplicates. If duplicates are allowed, then yes, use Collections.sort on the ArrayList when you're done adding to them. Or look in the Apache Commons or Google collection classes - I don't know them off the top of my head, but I'm sure there is a sorted List that allows duplicates in one or both of them.
result.get(thisWord).add(nextWord);
Collections.sort(result.get(thisWord));
Y Don't you try some thing like this
Collections.sort(inputWords);

Categories