Counting Duplicates and Grouping in an Arraylist - java

for my project we have to manipulate certain LISP phrasing using Java. One of the tasks is given:
'(A A A A B C C A A D E E E E)
Group the duplicates and make the output like:
′((4A)(1B)(2C)(2A)(1D)(4E))
Notice how the first four A's are kept separate from the last 2...
My issues is with keeping track of how many is each letter. I added the given letters into an array list and I manipulated it a little:
for (int i=0;i<list.size();i++)
{
String val=list.get(i);
String first=list.get(0);
while (val.equals(first))
{
total+=1;
val="X";
}
}
Total should be the number of times of the first occurrence but it keeps giving me 6. 6 is the correct number for all the A's in the sequence, but how do I get it to stop at the first four, record the number and move on the the next letter?

Here is with Java 8 Stream API.
Map<Character, Long> countedDup = Arrays.asList('A' ,'A' ,'A', 'A', 'B', 'C', 'C', 'A', 'A', 'D', 'E', 'E', 'E', 'E')
.stream().collect(Collectors.groupingBy(c -> c, Collectors.counting()));
System.out.println(countedDup);//{A=6, B=1, C=2, D=1, E=4}

This is my solution:
for (int i = 0; i < list.size(); i++) {
String first = list.get(i);
int total = 1;
while (i + 1 < list.size() && first.equals(list.get(i + 1))) {
total++;
i++;
}
System.out.println("(" + total + first + ")");
}
You can debug to know how it run.
***** Note that when compare 2 String objects, never use ==. Use method equals()

This is my solution, though didn't used arrayList:
Edited: as per pointed out by Ascalonian
String text = "'(A A V A B C C X X X X A A Z Z Z K L N N N N N)";
int counter = 1;
System.out.print("'(");
for (int i = 2; i < text.length() - 1; i = i + 2) {
System.out.print("(");
while (((i + 2) < text.length())
&& (text.charAt(i) == text.charAt(i + 2))) {
++counter;
i += 2;
}
System.out.print(counter + "" + text.charAt(i) + ")");
counter = 1;
}
System.out.print(")");
o/p will be for sample text:
((2A)(1V)(1A)(1B)(2C)(4X)(2A)(3Z)(1K)(1L)(5N))

Not sure if using an ArrayList is a requirement, but if not, I use a different approach where I get just the letters, strip away the white spaces, make it a char[] and iterate each letter.
// the initial LISP phrase
String lispPhrase = "'(A A A A B C C A A D E E E E)";
// Pull out just the letters
String letters = lispPhrase.substring(2, lispPhrase.length()-1);
// Remove the white space between them
letters = letters.replaceAll("\\s","");
// Get an array for each letter
char[] letterArray = letters.toCharArray();
char previousLetter = ' ';
char nextLetter = ' ';
int letterCounter = 1;
System.out.print("'(");
// now go through each letter
for (char currentLetter : letterArray) {
// If the first time through, set previousLetter
if (previousLetter == ' ') {
previousLetter = currentLetter;
}else {
nextLetter = currentLetter;
// Is the next letter the same as before?
if (previousLetter == nextLetter) {
letterCounter++;
}else {
// If the next letter is different, print out the previous letter and count
System.out.print("(" + letterCounter + previousLetter + ")");
// Reset the counter back to 1
letterCounter = 1;
}
previousLetter = nextLetter;
}
}
System.out.print("(" + letterCounter + previousLetter + "))");
This gives the output of:
'((4A)(1B)(2C)(2A)(1D)(4E))

In order to get the required output that you specified in your question, I would keep track of the current and next values in the given list. The element count starts at 1 and is incremented when the equality condition is true, otherwise it is reset to 1. And the final output is only updated when the equality condition is false.
Sample code:
EDIT I updated my code based on #Ascalonian's suggestion.
String inputString = "'(A A A A B C C A A D E E E E)";
// I assume that the input always starts with "'("
String finalOutput = inputString.substring(0, 2);
int valCount = 1;
String valCurrent = inputString.substring(2, 3);
String valNext = "";
for (int i = 4; i < inputString.length(); i++) {
valNext = inputString.substring(i, i + 1);
if (valNext.equals(" ")) {
continue;
}
if (valCurrent.equals(valNext)) {
valCount++;
} else {
finalOutput += "(" + valCount + valCurrent + ")";
valCount = 1;
}
valCurrent = valNext;
}
finalOutput += ")";
System.out.println(finalOutput);
Output string: '((4A)(1B)(2C)(2A)(1D)(4E))
I hope this helps.

Related

Caesar cipher by comparing char array with two arrays

I need to build a Caesar cipher that only encrypts letters, but no special characters. My concept was, to compare the input char[] with two alphabet char[]. If there is no match in a char, the char should be added to the String without being changed. The problem is that the not-changed char will be added to the String until the the for-loop ends. How do I fix this?
public static String encrypt(String text, int number) {
String str = "";
char[] chars = text.toCharArray();
char[] al = "abcdefghijklmnopqrstuvwxyz".toCharArray();
char[] ab = "abcdefghijklmnopqrstuvwxyz".toUpperCase().toCharArray();
for (char c : chars) {
boolean match = false;
for (int i = 1; i < chars.length - 1; i++) {
for (int k = 0; (k < al.length || k < ab.length) && !match; k++) {
match = (c == al[k] || c == ab[k]);
if (match) {
c += number;
str += c;
}
}
if (!match) {
str += c;
}
}
}
return str;
}
I already tried to put the case for not changing the string within the other for-loop, but it will be added until the for-loop has reached it's end.
I would tackle the problem by iterating through the String and considering the possible cases for each letter
Uppercase Letter
Lowercase Letter
Special Character
public static String encrypt(String text, int number) {
//String to hold our return value
String toReturn = "";
//Iterate across the string at each character
for (char c : text.toCharArray()){
if (Character.isUpperCase(c)){
/* If uppercase, add number to the character
If the character plus number is more than 90,
subtract 25 [uppercase letters have ASCII 65 to 90] */
toReturn += c + number > 90 ? (char)(c + number - 25) : (char)(c + number);
} else if (Character.isLowerCase(c)){
/* If lowercase, add number to the character
If the character plus number is more than 122,
subtract 25 [uppercase letters have ASCII 97 to 122] */
toReturn += c + number > 122 ? (char)(c + number - 25) : (char)(c + number);
} else {
// For other characters, just add it onto the return string
toReturn += c;
}
}
return toReturn;
}
Explanation of Code
You might be wondering what the following code does
toReturn += c + number > 90 ? (char)(c + number - 25) : (char)(c + number)
The structure is
toReturn += CONDITION ? A : B
It basically reads as
IF CONDITION IS TRUE, toReturn += A, ELSE toReturn += B
The CONDITION is simply c + number > 90 since we want to make sure that we are sticking with uppercase letters only
When this is true (A), we subtract 25 from c + number, otherwise (B) we just keep it as c + number (B)
We then cast this value into a char since it is initially an int

Java - queastion on purpose of (char){Alphabet - "a" + "z" + 1}

Essentially, I am confused on the purpose of this code and what it does ( cAlphabet = (char)(cAlphabet - 'a' + 'z' + 1); ), in this encryption code, could someone please explain how this works thanks!
System.out.println(" Input the ciphertext message : ");
String ciphertext = sc.nextLine();
System.out.println(" Enter the shift value : ");
int shift = sc.nextInt();
String decryptMessage = "";
for (int i = 0; i < ciphertext.length(); i++)
{
// Shift one character at a time
char alphabet = ciphertext.charAt(i);
// if alphabet lies between a and z
if (alphabet >= 'a' && alphabet <= 'z')
{
// shift alphabet
alphabet = (char)(alphabet + shift);
// shift alphabet less than 'a'
if (cAlphabet < 'a')
{
//reshift to starting position
cAlphabet = (char)(cAlphabet - 'a' +'z' + 1);
}
cAlphabet = (char)(cAlphabet - 'a' + 'z' + 1);
When you make some operations(sum, minus, etc) with Char it wiil use numeric code of character. So you will get new numeric code and convert it back to the character.
this is almost the same as cAlphabet = (char)(cAlphabet - 219 + 97 + 1);

How do I shift array characters to the right in Java?

This is what I have:
class encoded
{
public static void main(String[] args)
{
String s1 = "hello";
char[] ch = s1.toCharArray();
for(int i=0;i<ch.length;i++)
{
char c = (char) (((i - 'a' + 1) % 26) + 'a');
System.out.print(c);
}
}
}
So far I've converted the string to an array, and I've worked out how to shift, but now I'm stuck.
What I want is for the code to start at ch[0], read the character, shift it one to the right (h to i) and then do the same for each character in the array until it reaches the end.
Right now, my code outputs opqrs. I want it to output ifmmp. If I replace the int i = 0 in the for loop with int i = ch[0], it does start at i, but then it just inputs ijklmno...
I want it to read h, output as i, read e, output as f, and so on until it reaches the end of the array.
You are using the loop index i instead of the ith character in your loop, which means the output of your code does not depend the input String (well, except for the length of the output, which is the same as the length of the input).
Change
char c = (char) (((i - 'a' + 1) % 26) + 'a');
to
char c = (char) (((ch[i] - 'a' + 1) % 26) + 'a');
Replace i - 'a' + 1 with ch[i] - 'a' + 1
class encoded {
public static void main(String[] args)
{
String s1 = "hello";
char[] ch = s1.toCharArray();
for(int i=0;i<ch.length;i++)
{
char c = (char) (((ch[i] - 'a' + 1) % 26) + 'a');
System.out.print(c);
}
}
}

Issue assigning a value for each character of input and display the value for input

I'm trying to create a program that accepts user input, scans each substring and checks if that character matches a position in the alphabet and if it does I want to get the equivalent position in the score String to get the score for that character and display the score for each character and the overall total.
What I have in my code below should have completed each part of what I'm trying to do, but there's a problem with the second for loop which I cannot find the solution for, I think it may be with the substrings inside the loops but I'm not sure.
import java.util.*;
import java.io.*;
public class testt
{
public static void main(String [] args) throws IOException
{
String alpha = "abcdefghijklmnopqrstuvwxyz";
String score = "13321424185131139111144849";
String result = "";
int value = 0, total = 0;
Scanner in = new Scanner(System.in);
System.out.print("Enter word: ");
String input = in.nextLine();
if(input == null || input.length() == 0)
{
System.out.println("Enter input.");
System.exit(0);
}
String inputLower = input.replaceAll("[^a-zA-Z ]", "").toLowerCase();
String inputArray[] = inputLower.split("\\s+");
for(int i = 0; i < alpha.length(); i++)
if(inputLower.substring(i, i + 1) == alpha.substring(i, i + 1))
{
value = Integer.parseInt(score.substring(i, i + 1));
if(value == 9)
value++;
result += inputLower.substring(i, i + 1) + " will give you " + value + " point(s)\n";
total += value;
}
else if(i == alpha.length() + 1)
{
System.out.println(result + "This word will earn you: " + total);
System.exit(0);
}
}
}
Any advice or tips I would really appreciate since I think I have the program mostly finished.
Here's question that I'm studying from http://i.imgur.com/ftfcINX.jpg
Your actual code shows main problems from which I will state that:
You are looping throught alpha.length and you are risking to get
into a StringIndexOutOfBoundsException so better check if i
isn't greater than input.length.
You are using substring(i,i+1) to get a character at the position
i which you can replace with .charAt(i) which is designed for this.
You are exiting the application if a character in agiven word
doesn't match its correspending one in alpha so you are quiting
without checking all the characters of the input...
I tried to correct your code and here's the result I came up with:
String alpha = "abcdefghijklmnopqrstuvwxyz";
String score = "13321424185131139111144849";
String result = "";
int value = 0, total = 0;
Scanner in = new Scanner(System.in);
System.out.print("Enter word: ");
String input = in.next();
for(int i = 0; i < input.length(); i++) {
if( i<alpha.length()) {
if(input.charAt(i) == alpha.charAt(i))
{
value = Integer.parseInt(score.charAt(i)+"");
if(value == 9)
value++;
result += input.charAt(i) + " will give you " + value + " point(s)\n";
total += value;
}
}
}
System.out.println(result + "This word will earn you: " + total);
And here's a Live DEMO with alcme as input and gives this result:
a will give you 1 point(s)
c will give you 3 point(s)
e will give you 1 point(s)
This word will earn you: 5
Since you may have multiple words in inputArray, you need two nested loops instead of a single loop. The loop should walk inputArray one by one, then inside of that array it should walk the letters of the alphabet and do the scoring:
String alpha = "abcdefghijklmnopqrstuvwxyz";
// a b c d e f g h i j k l m n o p q r s t u v w x y z
int[] score = {1,3,3,2,1,4,2,4,1,8,5,1,3,1,1,3,10,1,1,1,1,4,4,8,4,10};
int total = 0;
for (String word : inputArray) {
int wordTotal = 0;
for(int i = 0; i < word.length(); i++) {
char letter = word.charAt(i);
int pos = alhpa.indexOf(letter);
int value = score[pos];
System.out.println("Letter "+letter+" will earn you: " + value);
// Increment wordTotal, not total
wordTotal += value;
}
System.out.println("Word "+word+" will earn you: " + wordTotal);
total += wordTotal;
}
System.out.println("Total for all words: " + total);
Here are a few implementation notes:
Using an array of integers instead of an array of characters would let you avoid "encoding" ten as '9', and help you drop the if (value == 9) hack.
Rather than using substrings and looking up words in a string, use indexOf for the char, and use that index to look up into the array of scores.
My two cents I suppose, I was abit late.
You could put the actual score code into a function and call it in your loop
public class Test {
public static void main(String[] args) throws IOException {
int total = 0;
Scanner in = new Scanner(System.in);
System.out.print("Enter word: ");
String input = in.nextLine();
// Close the input stream to avoid memory leaks
in.close();
if (input == null || input.length() == 0) {
System.out.println("Enter input.");
System.exit(0);
}
String inputLower = input.replaceAll("[^a-zA-Z ]", "").toLowerCase();
String inputArray[] = inputLower.split("\\s+");
// Loop through each entered word, I only did this step because you appeared to split up the input even though the Array wasn't actually being used in your original program
for(String word : inputArray) {
int currentWordTotal = 0;
// Use a method to get the value for each letter in the current word
for(int i = 0; i < word.length(); i++) {
currentWordTotal += letterScore(word.charAt(i));
}
// Print out the word total
System.out.println("Word: " + word + ", will earn you: " + currentWordTotal + " points.");
// Keep track of all word total in the event that multiple words were entered
total += currentWordTotal;
}
// Print out the total for all words
System.out.println("Your Total for the entered Words: " + total);
}
private static int letterScore(char letter) {
char[] letters = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't','u', 'v', 'w', 'x', 'y', 'z'};
int[] scores = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 9, 1, 1, 1, 1, 4, 4, 8 ,4 ,10};
// Here we look through the array of letters, when we find a match we use the index of the character array to get the corresponding value from the score array
for(int i = 0; i < letters.length; i++) {
if(letters[i] == letter) {
return scores[i];
}
}
return 0;
}
}

algorithm to create a char array from permutations list in java

I'm sorry for the slightly confusing title, I'm unsure of how to phrase it.
I need to create a char array allowing for every possible permutation of a character set.
If I were to give you:
char[] charSet = {"a", "b", "c"};
BigInteger value = n; //where n is a number >= 0
char[] charArray = createCharArray(value, charSet);
How can I create charArray from value and charSet such that if I ran:
createCharArray(new BigInteger("6"), {"a", "b", "c"});
it would return {"a", "c"}
because
a=1
b=2
c=3
aa=4
ab=5
ac=6
Here's what I have so far:
private char[] createCharArray(BigInteger value, char[] charSet){
List<Character> charArray = new ArrayList<Character>();
if (value.compareTo(this.max) == 0)
System.out.println("");
BigInteger csSize = new BigInteger(String.valueOf(charSet.length));
if(this.powers.isEmpty())
this.powers.add(0, csSize.pow(0));
if(this.sumPowers.isEmpty())
this.sumPowers.add(0, csSize.pow(0));
BigInteger curPow;
int i = 1;
while((curPow = csSize.pow(i)).compareTo(value) <= -1){
if(this.powers.size() <= i)
this.powers.add(i, curPow);
if(this.sumPowers.size() <= i)
this.sumPowers.add(i, this.sumPowers.get(i-1).add(curPow));
i += 1;
}
i -= 1;
while (i >= 0 && value.compareTo(BigInteger.ZERO) >= 0){
if (i <= 1){
int charNum = value.divide(this.sumPowers.get(0)).intValue() - 1;
charArray.add(charSet[charNum]);
}
else{
int charNum = value.divide(this.sumPowers.get(i-1).subtract(BigInteger.ONE)).intValue() - 1;
charArray.add(charSet[charNum]);
}
value = value.subtract(this.powers.get(i));
i -= 1;
}
char[] returnArray = new char[charArray.size()];
int j = 0;
while(j<charArray.size()){
returnArray[j] = charArray.get(j);
j += 1;
}
return returnArray;
}
It certainly could use some help, as a value of 0 fails, values of 1 and 2 succeed, 3-8 fail, 9, 10 succeed, etc.
EDIT: To be clear, the value parameter must be able to be ANY number n > 0. This is why I've chosen BigInteger
Make a class that has two fields:
private char letter;
private int value;
public <classname>(char letter){
this.letter = letter;
value = 0;
}
//Setters and getters
Then in your main when initializing an array (via for loop) set the value to i + 1 (getting rid of 0)
for(int i = 0; i < <yourarray>.length; i ++){
//Assuming you initialized your objects before
<yourarray>[i].<setterforvalue>(i + 1);
}
And then to calculate them together:
for(int i = 0; i < <yourarray>.length; i ++){
for(int j = 0; j < <yourarray>.length; j ++){
if(<yourarray>[i] + <yourarray>[j] == <needednumber>){
//Do what you need to do with the value
}
}
}
Okay after much thinking and eventually breaking it down to using numbers 0-9 instead of characters. Here's the breakdown: Think about how regular base 10 numerals are created.
The number 194 is made up of a 4 in the ones column, a 9 in the tens, and a 1 in the hundreds. The difference between ones, tens, and hundreds is multiplication/division by 10, which is the base.
So I figured that I could mod the 194 by the base (10) to get 4, the ones. then divide by 10 to remove the ones column. mod again to get 9, then divide by 10, mod again to get 1, divide by 10. once the division creates a number that is exactly 0, we are done. This is because we cannot make a number 000194.
For my function, My base is the length of the character set, and the value is like 194 in the example above.
private static void createCharArray(BigInteger value, char[] charSet){
List<Character> charArray = new ArrayList<Character>();
BigInteger csSize = BigInteger.valueOf(charSet.length);
if (value.compareTo(BigInteger.ZERO) == 0)
charArray.add(0, charSet [0]);
else{
BigInteger modded = value.mod(csSize);
BigInteger digit = value.divide(csSize);
while (modded.compareTo(BigInteger.ZERO) != 0 || digit.compareTo(BigInteger.ZERO) != 0){
if(modded.compareTo(BigInteger.ZERO) == 0){
charArray.add(0, charSet[csSize.subtract(BigInteger.ONE).intValue()]);
value = value.subtract(BigInteger.ONE);
}
else
charArray.add(0, charSet[modded.subtract(BigInteger.ONE).intValue()]);
value = value.divide(csSize);
modded = value.mod(csSize);
digit = value.divide(csSize);
}
}
for(char c : charArray)
System.out.print(c);
System.out.println();
}
public static void main(String[] args) {
long start = System.nanoTime();
String characters = "";
characters += "0123456789";
characters += "abcdefghijklmnopqrstuvwxyz";
characters += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
characters += " !\"#$%&'()*+,-./:;<=>?#[\\]^_`{|}~";
char[] cs = characters.toCharArray();
Arrays.sort(cs);
createCharArray(new BigInteger("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), cs);
long total = System.nanoTime() - start;
System.out.println("Completed in: " + total + " billionths of a second");
System.out.println("Completed in: " + total/1000000 + " thousandth(s) of a second");
}
If you run this, note that that BigInteger 4 lines from the bottom is 100 characters long. On my machine, it takes only 1/1000 th of a second (1 Millisecond).

Categories