I have two arrays :
String[] matnr = new String[] { "16400", "56000", "56000", "50000", "16400" };
String[] lfimg = new String[] { "4.000", "5.000", "6.000", "9.000", "10.560" };
I want to find sum of lfimg items having same matnr value i.e. for matnr 16400 sum output will be 14.560, for 56000 output will be 11.000 and matnr 50000 sum output will be 9.000
below block is written by me :
public static void main(String[] args) {
String[] matnr = new String[] { "16400", "56000", "56000", "50000", "16400" };
String[] lfimg = new String[] { "4.000", "5.000", "6.000", "9.000", "10.56" };
int n = matnr.length;
int i, j, x;
int count = 0;
int count1 = 0;
double value = 0.0;
// calculate unique material count
for (i = 0; i < n; ++i)
System.out.println(i + 1 + "compartment material : " + matnr[i]);
for (i = 0; i < n; i++) {
for (j = 0; j < i; j++)
if (matnr[i] == matnr[j])
break;
if (i == j) {
count = count + 1;
}
}
System.out.println("final count >>" + count);
String materialArray[] = new String[count];
for (i = 0; i < n; i++) {
for (j = 0; j < i; j++)
if (matnr[i] == matnr[j])
break;
if (i == j) {
materialArray[count1] = matnr[i];
System.out.println("Material array xxxx >>" + materialArray[count1]);
System.out.println("count1 before >>" + count1);
count1 = count1 + 1;
System.out.println("count1 after >>" + count1);
}
}
System.out.println("matnr.length >>" + matnr.length);
System.out.println("materialArray.length >>" + materialArray.length);
for (i = 0; i < matnr.length; i++) {
System.out.println("111Value >>> " + matnr[i]);
}
for (j = 0; j < materialArray.length; j++) {
System.out.println("222Value >>> " + materialArray[j]);
}
System.out.println("---- ******* ------------ *********** -------- ********** ------");
for (i = 0; i < materialArray.length; i++) {
for (j = 0; j < matnr.length; j++) {
if (materialArray[i].contains(matnr[j])) {
value = value + Double.parseDouble(lfimg[j]);
System.out.println("Value1 >>> " + value);
}
}
}
}
But I'm not getting desired output. It is coming as :
Value1 >>> 4.0
Value1 >>> 14.56
Value1 >>> 19.560000000000002
Value1 >>> 25.560000000000002
Value1 >>> 34.56
Where as I want output as :
Value1 >>> 14.560
Value1 >>> 11.000
Value1 >>> 9.000
Can anybody please assist in this regard.
You do not reset the value variable in your final forloop, hence why you're getting ever increasing numbers in your print, ending in 34.56. You want one value for each materialArray entry, so immediately after for (i = 0; i < materialArray.length; i++) {, you'd want value = 0.
You're using materialArray[i].contains(matnr[j]) - that's asking if matnr[j] is a substring of materialArray[i]. It seems rather clear you wanted equals instead. Minor nit and doesn't break here, but a bug nonetheless.
Your printer tool will print every time an individual entry matches, and prints nothing after you're gone through the whole list, resulting in this weird output. Your intent, presumably, is to let the inner loop (for (int j = 0; j < matnr.length; j++)) complete, and THEN you want to print. Thus, your sysout statement needs to be shifted two lines down, after the closing bracket of the inner for loop. Combine that with resetting your value and...
Value1 >>> 14.56
Value1 >>> 11.0
Value1 >>> 9.0
NB: A second issue is rounding errors. You basically should never toString() or otherwise directly print a float or double value. If you do, you get wonky weirdness like 19.560000000000002.
If I ask you, using decimal notation, to write down the result of 'one third', you must round. You can't write an infinite processing of .3333333, right? Computers (specifically, doubles and floats) are no different, but computers count in binary, not decimal. So, the computer has to round a bit, and then 'render' the value it has in decimal, and this is where the weirdness comes from. The inaccuracies introduced by this rounding cannot be avoided (at least, not with doubles and floats), but usually the inaccuracies do not creep into the relevant significance of your numbers. The solution is therefore to ALWAYS guide the libraries when printing your numbers, by telling it how many digits you are expecting. So, make it:
System.out.printf("Value1 >>> %.4f\n", value);
The %.4f tells the printer to print with no more than 4 digits after the dot, and printf does not automatically newline, so the \n tells it to print that newline explicitly.
Finally, there's the matter of this code style. This can be done far simpler (and more efficiently) using java's built in tools, such as HashMap:
public static void main(String[] args) {
String[] matnr = new String[] { "16400", "56000", "56000", "50000", "16400" };
String[] lfimg = new String[] { "4.000", "5.000", "6.000", "9.000", "10.56" };
var values = new HashMap<String, Double>();
// load values into the map.
for (int i = 0; i < matnr.length; i++) {
double z = Double.parseDouble(lfimg[i]);
values.compute(matnr[i], (m, v) -> v == null ? z : v + z); // [1]
}
// print them to show it works
for (var e : values.entrySet()) {
System.out.printf("%s: %.4f\n", e.getKey(), e.getValue());
}
}
The key line is the line marked [1]: It says: To compute the value for the value at the current matnr entry, if there is no existing value yet (v would be null), it's just the corresponding entry from lfimg, and if there is an existing value, it is the sum of what we had, plus the corresponding entry from lfimg.
Related
So one of the conditions for the credit card number to be valid is that "the sum of first 4 digits must be 1 less than the sum of the last 4 digits" I believe the problem could be it's counting the dashes as a digit but not sure. the rule 4 is that the sum of all digits must be divisible by 4, which seems to work, but rule 5 doesn't.
int sum = ccNumber.chars().filter(Character::isDigit).map(Character::getNumericValue).sum();
if(sum%4!=0){
valid = false;
errorCode = 4;
return;
}
// set values and for loop for fifth rule.
String digits = ccNumber.replaceAll("[ˆ0-9]","");
int firstfourdigits = 0;
int lastfourdigits = 0;
for(int i=0; i<4; i++)
firstfourdigits = firstfourdigits + Character.getNumericValue(ccNumber.charAt(i));
for (int i=0, m = ccNumber.length()-1; i<4; i++, m--)
lastfourdigits = lastfourdigits + Character.getNumericValue(ccNumber.charAt(m));
// mutator for fifth rule
if(lastfourdigits!= firstfourdigits -1){
valid = false;
errorCode = 5;
return;
}
sorry I'm lost and new to coding.
Edit since you altered your question. Original anwser to the original question is at the bottom part
Checking if first part and last part have a difference of one
The code you currently have is close, but there are some mistakes here and there.
Filtering out only digits: The code you use to filter out all characters that are not numeric should work, but in your following code you are no longer using this filtered value in your loop.
firstfourdigits + Character.getNumericValue(ccNumber.charAt(i));
This should use the variable with only your numeric values => digits
firstfourdigits = firstfourdigits + Character.getNumericValue(digits.charAt(i));
Difference in first group vs last group: The -1 should be replaced by +1 here. When you are experiencing problems with this type of checks, it's always adviced to try and calculate it on a piece of paper. Lets assume the sum of the first 4 digits is 8 and the sum of the last 4 digits is 9. As per the requirement, this is a valid number, and should result to false in your check if(lastfourdigits!= firstfourdigits -1)
Let's fill it in: 9 != 8-1 => 9 != 7 so this returns false, and marks it as invalid. If we base it on the requirement, you could write the sum of the first 4 digits should be one less then the last 4 digits as: firstfourdigits = lastfourdigits - 1. This is mathmatically the same as lastfourdigits = firstfourdigits + 1. However, in our check we want to know if this check is not correct, so we should change the statement to: if(lastfourdigits != firstfourdigits + 1)
These 2 changes should give you the results you asked for. Combining these changes, we come to the following code example
String digits = ccNumber.replaceAll("[ˆ0-9]", "");
int firstfourdigits = 0;
int lastfourdigits = 0;
for (int i = 0; i < 4; i++)
firstfourdigits = firstfourdigits + Character.getNumericValue(digits.charAt(i));
for (int i = 0, m = ccNumber.length() - 1; i < 4; i++, m--)
lastfourdigits = lastfourdigits + Character.getNumericValue(digits.charAt(m));
if(lastfourdigits!= firstfourdigits + 1){
valid = false;
errorCode = 5;
return;
}
Other recommendations
The above example should work for what you asked, and is based on your code. However there are some optimalisations possible to the code to make everything more readable
Use brackets on your for loop: To make it clearer what is inside the for loop, and what isn't, I would advise you to make use of curly brackets. Though they are not required, they will make it very clear what is and isn't in the for loop and will prevent hard to spot issues when you add something extra in the for loop
Use the short notation for addition: Instead of writing firstfourdigits = firstfourdigits + Character.getNumericValue(digits.charAt(i));, You could use a shorter notation of +=. This will take the value on the left side of your equals, and will calculate the sum of that value on the right side. firstfourdigits += Character.getNumericValue(digits.charAt(i));
The code looks like this then:
String digits = ccNumber.replaceAll("[ˆ0-9]", "");
int firstfourdigits = 0;
int lastfourdigits = 0;
for (int i = 0; i < 4; i++){
firstfourdigits += Character.getNumericValue(digits.charAt(i));
}
for (int i = 0, m = ccNumber.length() - 1; i < 4; i++, m--) {
lastfourdigits += Character.getNumericValue(digits.charAt(m));
}
if(lastfourdigits!= firstfourdigits + 1){
valid = false;
errorCode = 5;
return;
}
Anwser to original question to calculate the sum of all digits
You could make use of Character.isDigit(char). To simplify the for loop, you can even make use of a stream to get the sum
int sum = ccNumber.chars().filter(Character::isDigit).map(Character::getNumericValue).sum();
if (sum % 4 != 0) {
valid = false;
errorCode = 4;
return;
}
.chars(): This will create a stream of all the characters in the provided string so that we can loop over them one by one
.filter(Character::isDigit): This will filter out every character that is not a digit
.map(Character::getNumericValue): This will map the stream from Characters to their numeric values so that we can use those further
sum() will calculate the sum of the numeric values that we currently have in the Stream
The difference is always a positive value e.g. the difference between 4 and 5 or between 5 and 4 is the same i.e. 1. In other words, you need to compare the absolute value of the subtraction with 1.
Therefore, replace
if(lastfourdigits!= firstfourdigits -1)
with
if(Math.abs(lastfourdigits - firstfourdigits) != 1)
Another mistake in your code is that you have used ccNumber, instead of digits in your loops.
Some recommendations to make your code easier to understand:
Replace for (int i=0, m = digits.length()-1; i<4; i++, m--) with for (int m = digits.length() - 1; m >= digits.length() - 4; m--). Note that I've already replaced ccNumber, with digits in these statements.
Replace ccNumber.replaceAll("[^0-9]","") with ccNumber.replaceAll("\\D", "").
Replace firstfourdigits = firstfourdigits + Character.getNumericValue(digits.charAt(i)) with firstfourdigits += Character.getNumericValue(digits.charAt(i)). Note that I've already replaced ccNumber, with digits in these statements.
Always enclose the body of if and loop statements within { } even if there is just one statement inside the body.
Demo:
public class Main {
public static void main(String[] args) {
System.out.println(isValidOnDiffCriteria("1234-5678-9101-1213"));
System.out.println(isValidOnDiffCriteria("1234-5678-9101-1235"));
System.out.println(isValidOnDiffCriteria("1235-5678-9101-1234"));
}
static boolean isValidOnDiffCriteria(String ccNumber) {
String digits = ccNumber.replaceAll("\\D", "");
int firstfourdigits = 0;
int lastfourdigits = 0;
for (int i = 0; i < 4; i++) {
firstfourdigits += Character.getNumericValue(digits.charAt(i));
}
for (int m = digits.length() - 1; m >= digits.length() - 4; m--) {
lastfourdigits += Character.getNumericValue(digits.charAt(m));
}
if (Math.abs(lastfourdigits - firstfourdigits) != 1) {
return false;
}
return true;
}
}
Output:
false
true
true
Try the code above. Should be what you asked. You don't need a try catch.
static boolean isCardValid(String creditCard) {
// group digits in a string array
String[] cards = creditCard.split("-");
int sumAll = 0;
// for every group of digits we convert it to char[]
for (String card : cards) {
sumAll += sum(card.toCharArray());
}
int firstGroupOfDigits = sum(cards[0].toCharArray()) ;
int lastGroupOfDigits = sum(cards[cards.length-1].toCharArray());
if( firstGroupOfDigits == lastGroupOfDigits -1){
if (sumAll % 4 == 0) {
return true;
}
}
return false;
}
// sum the group of digits separated by "-"
static int sum(char[] chr) {
int sum = 0;
for (char c : chr) {
sum += Character.getNumericValue(c);
}
return sum;
}
Well, your program is not that bad and as far as I can tell there is only one problem and that is the you simply reversed the required test on the first and last groups. I would advise you to ensure the valid is initialized to true as the default. Then if none of the error codes are set, it will return true.
Presently you have the following:
if (lastfourdigits != firstfourdigits - 1) {
valid = false;
errorCode = 5;
}
But what you need is this
if (lastfourdigits != firstfourdigits + 1) {
valid = false;
errorCode = 5;
}
Your also have the following, unnecessary code.
String digits = ccNumber.replaceAll("[ˆ0-9]","");
The reason being is that you are simply using ccNumber starting at the beginning for the first four characters and starting at the end for the last four. In this way you are not encountering dashes so you don't need to get just the digits.
Another recommendation is that as soon as you find an error you set the error code and return immediately. What's the use in continuing to process a card that has already been found to be flawed?
Other considerations and an alterative approach
It may not be a part of the assignment but I would also consider the following:
What if you have more or less than 16 digits?
What if you have more than three dashes giving more than four groups of numbers.
Checking the above would require additional logic and would complicate your effort. But it is something to consider. What follows demonstrates one way to check on those particular format issues and report them. This uses basic techniques and avoids streams so as not to repeat unnecessary operations.
This example throws selective errors based on problems found. Those may be changed or eliminated altogether as explained later. Credit card validation is a task where the most straightforward solution is best and should require low overhead.
First, declare a special exception to catch credit card errors.
class BadCreditCardException extends Exception {
public BadCreditCardException(String message) {
super(message);
}
}
Now declare some test data.
String[] testData = {
"1234-4566-9292-0210",
"1500-4009-2400-1600",
"1500-4009-2400-160000",
"1234-45669292-0210",
"1#34-45-66-9292-0210",
"1234-45B6-9292-0210",
"1234-4566-9292-2234",
"1234-4566-9292-021022",
"1234-4566-9292-0210",
"4567-4566-92!2-6835",
"1234-4566-9292-0210",
"1234-45+6-9292-0210",
"1234-4566-92x2-0210",
"1234-4566-9292-0210",
};
Test the credit cards and report errors. Note that only first encountered errors are reported. There may be multiple errors in the number.
String fmt = "%-23s - %s%n";
for(String card : testData) {
try {
validate(card);
System.out.printf(fmt,card, "Valid");
} catch (BadCreditCardException bce) {
System.out.printf(fmt,card, bce.getMessage());
}
}
The above prints.
1234-4566-9292-0210 - Invalid credit card checksum
1500-4009-2400-1600 - Valid
1500-4009-2400-160000 - Non group of 4 digits
1234-45669292-0210 - Insufficient or too may dashes
1#34-45-66-9292-0210 - Insufficient or too may dashes
1234-45B6-9292-0210 - Non digit found.
1234-4566-9292-2234 - Valid
1234-4566-9292-021022 - Non group of 4 digits
1234-4566-9292-0210 - Invalid credit card checksum
4567-4566-92!2-6835 - Non digit found.
1234-4566-9292-0210 - Invalid credit card checksum
1234-45+6-9292-0210 - Non digit found.
1234-4566-92x2-0210 - Non digit found.
1234-4566-9292-0210 - Invalid credit card checksum
The Explanation
The validate method. The method works as follows.
split the card into groups using the dash (-) as a delimiter.
If there are not four groups, throw an exception.
Otherwise, sum each of the groups as follows each of these is checked during the summation process.
first check that the group is of size four, if not throw an exception.
as the group characters are iterated, if a non-digit is encountered, throw an exception.
otherwise, continue computing the sum for the current group as follows:
If the character is a digit, subtract 0 to convert it to an int
and add to the current sums array element.
when completed, add that group sum to the totalSum of all digits.
if the totalSum is divisible by four and the first group is one less than the last group, it is a valid card. Otherwise, throw an exception.
Alternative error handling modification
If the exceptions are not wanted, but just a pass or fail indication, then make the following changes.
change the void return type to boolean
if an exception was throw, simply return false
if all tests pass, then the last statement should return true
public static void validate(String cardNumber) throws BadCreditCardException {
int [] groupSums = new int[4];
int totalSum = 0;
String [] groups = cardNumber.split("-");
if (groups.length != 4) {
throw new BadCreditCardException("Insufficient or too may dashes");
}
for (int i = 0; i < groupSums.length; i++) {
if (groups[i].length() != 4) {
throw new BadCreditCardException("Non group of 4 digits");
}
for(int digit : groups[i].toCharArray()) {
if (!Character.isDigit(digit)) {
throw new BadCreditCardException("Non digit found.");
}
groupSums[i]+= digit -'0';
}
totalSum += groupSums[i];
}
if (groupSums[0]+1 != groupSums[3] || totalSum % 4 != 0) {
throw new BadCreditCardException("Invalid credit card checksum");
}
}
A separate class for Credit card and its parts
Add a Part class that manages a portion of the credit card
Add a CreditCard class that manages these portions
Valid each portion
In addition to validating each potion individually, validate additional check
Depending on the number of times, the valid & sumDigits method will be called, validation/sum can be added in respective methods or in constructor.
import java.util.Arrays;
public class CreditCard {
private final String input;
private final Part[] parts;
private final boolean valid;
CreditCard(String card) {
this.input = card;
if (card == null || card.length() != 19) {
valid = false;
parts = null;
} else {
parts = Arrays.stream(card.split("-")).map(Part::new).toArray(Part[]::new);
final int totalSum = Arrays.stream(parts).mapToInt(Part::sumDigits).sum();
valid = totalSum % 4 == 0 && parts.length == 4
&& parts[0].sumOfDigits + 1 == parts[3].sumOfDigits
&& Arrays.stream(parts).allMatch(Part::isValid);
}
}
static class Part {
final int num;
final boolean valid;
final int sumOfDigits;
Part(String part) {
int localNum = 0;
try {
localNum = Integer.parseInt(part);
} catch (Throwable ignored) {
}
this.num = localNum;
valid = part.length() == 4 && part.equals(String.format("%04d", num));
if (valid) {
sumOfDigits = part.chars().map(Character::getNumericValue).sum();
} else {
sumOfDigits = -1;
}
}
boolean isValid() {
return valid;
}
int sumDigits() {
return sumOfDigits;
}
}
public static void main(String[] args) {
String[] creditCards = {
"1000-0000-0001-0002",
"0000-0000-0000-0000",
"10000-0000-0001-0002",
"10000000-0001-0002",
"1a00-0000-0001-0002",
"1234-4826-6535-1235",
};
Arrays.stream(creditCards).map(CreditCard::new)
.forEach(c -> System.out.println(c.input + " is " + c.valid));
}
}
Everything is fine except the second for loop and your if condition.
Replace your code with the following changes and it should work fine:
int firstfourdigits = 0, lastfourdigits = 0;
for(int i=0; i<4; i++)
firstfourdigits = firstfourdigits + Character.getNumericValue(ccNumber.charAt(i));
for (int m = ccNumber.length()-1; m>ccNumber.length()-5; m--)
lastfourdigits = lastfourdigits + Character.getNumericValue(ccNumber.charAt(m));
if(firstfourdigits != lastfourdigits - 1){
valid = false;
errorCode = 5;
return;
}
You do not need to extract digits at all.
public boolean ccnCheck(String ccn){
String iccn = ccn.replaceAll("-","");
int length = iccn.length();
int fsum = 0;
int lsum = 0;
int allsum = 0;
for( int i = 0; i < length; i++){
int val = Character.getNumericValue(iccn.charAt(m))
if( i < 4)
fsum += val;
if( i >= length-4)
lsum += val;
allsum += val;
}
if( (allsum % 4) != 0)
return false;
if( fsum != lsum-1 )
return false;
return true;
}
In your rule five check, you're using ccNumber instead of your digits string.
For example, shouldn't
Character.getNumericValue(ccNumber.charAt(i));
be this instead:
Character.getNumericValue(digits.charAt(i));
So I have some code which is finding the distance between a series of points. One method uses the euclidean distance and is working fine, the other is using Manhattan and I don't know why it isn't working.
I have it set up so that the distance of the first element in the array list is zero for both methods, and therefore should print that image 1 is a match. However the Manhattan method always returns image 31, no matter how many different elements I test it with. I have double checked the elements in the array list and it should be returning image 1.
Does anybody have any ideas? Thanks in advance
public void matchEuclidean(){
for(int i = 0; i < numberimages; i++){
distanceE[i][0] = weights[i][0] - testweights[0][0];
distanceE[i][1] = weights[i][1] - testweights[0][1];
}
for(int i = 0; i < numberimages; i++){
distanceEu[i] = (Math.pow(distanceE[i][0], 2)) + (Math.pow(distanceE[i][1], 2));
distanceEu[i] = Math.sqrt(distanceEu[i]);
}
for (double no : distanceEu) {
list.add(Double.valueOf(no));
}
double max= Collections.min(list);
double min = list.indexOf(max) + 1;
System.out.println("(euclidean) the unknown image matches image " + (min));
}
public void matchManhattan(){
for(int i = 0; i < numberimages; i++){
distanceM[i][0] = weights[i][0] - testweights[0][0];
distanceM[i][1] = weights[i][1] - testweights[0][1];
}
for(int i = 0; i < numberimages; i++){
distanceMu[i] = distanceM[i][0] + distanceM[i][1];
}
for (double no : distanceMu) {
listM.add(Double.valueOf(no));
}
double max= Collections.min(listM);
double min = listM.indexOf(max) + 1;
System.out.println("(Manhattan) the unknown image matches image " + (min));
}
It looks like you neglected to use the Math.abs function in Manhattan distance:
distanceMu[i] = Math.abs(distanceM[i][0]) + Math.abs(distanceM[i][1]);
Without it, you don't really have a valid "distance" function: you can get negative values, and the triangle inequality does not hold
int a[] = {6,22,33,12,44,9};
int low = a[0];
for(int i = 1 ; i < a.length ; i ++ )
{
if(a[i] < low)
{
low = a[i];
}
}
System.out.println("The smallest number is the given array is : " + low);
}
}
I have an unsorted array and I want to find all pairs in that array such that their difference (in absolute value) gives the x.
For example if x=8 and we have array {13, 1,-8, 21, 0, 9,-54, 17, 31, 81,-46} I would get:
Indices 0 & 3 with values 13 & 21 (e.g., 13-21= | 8 |)
Indices 1 & 5 with values 1 & 9
Indices 2 & 4 with values -8 & 0
Indices 6 & 10 with values -54 & -46
I made a solution but I'm not sure if it is O(n) or O(n^2). I tried to avoid a nested loop and instead keep two pointers i and j, but I still think it is O(n^2)? It kind of behaves like a nested loop.
int i = 0;
int j = 1;
System.out.println("All pairs of elements of the array that subtract exactly to absolute value of " + x + " are:");
while (i < A.length && j < A.length)
{
if (abs(A[i] - A[j]) == x)
{
System.out.println("Indices " + i + " & " + j + " with values " + A[i] + " & " + A[j]);
}
if (j != A.length - 1)
{
j++;
} else if (i == A.length - 1)
{
return;
} else
{
i++;
j = i + 1;
}
}
It kind of behaves like a nested loop
It's not just "kind of" -- you've hand-coded two loops, with the j-loop logically inside i-loop. The critical parts are:
i = 0
while i < limit {
...
i += 1
}
and
j = 1
while j < limit {
...
j = i+1
}
Each of these is the "while"-ish version of a for loop.
This, combined with your if-else logic, translates pretty well to
for i in 0 : limit {
for j in i+1 : limit {
}
}
you can use map to index your array values, then calculate the complement of target value, and search the complement's index in map, which is O(1) and inserting values into map is O(n), so the time complexity can be reduced to O(1), the code snippet is shown below
import java.util.*;
public class TwoDiff {
public static void main(String args[])
{
int arr[] = {13, 1,-8, 21, 0, 9,-54, 17, 31, 81,-46};
int target = 8;
List<int[]> res = twoDiff(arr, target);
res.forEach(l -> System.out.println(Arrays.toString(l)));
}
private static List<int[]> twoDiff(int[] arr, int target) {
Map<Integer, Integer> map = new HashMap<>();
List<int[]> resList = new ArrayList<>();
for(int i=0; i< arr.length; i++)
{
map.put(arr[i], i);
}
for (int i =0; i < arr.length; i++)
{
int complement = arr[i] - target;
if(map.containsKey(complement))
{
resList.add(new int[] {i, map.get(complement)});
}
}
return resList;
}
}
My code below prints out a letter frequency table (number of letter occurances in a string) that is inputted from a scanner class. I Have everything working correctly except the last bit. When executed, the table displays letters a-z and the number of occurrences except for the last method LargestLength() method. Since my array 'score' uses int[26], instead of using a-z it uses ints 0-25. (0=A, 1=B, etc.) As of now my LargestLength method only displays the number (instead of the letter) which comes up the most but does not count the number of occurrences.
For example, If my string were to be "Hello", l shows up most frequently so i would like it to display, "Most Frequent: l 2" but with my code it displays "Most Frequent: 11" (11 = L). How would I go about fixing this?
Profile Class.
public class LetterProfile {
int score[] = new int [26];
public void countChars (String s) {
s = s.toLowerCase();
char a = 'a';
for (int i = 0; i < s.length(); i++) {
int next = (int)s.charAt(i) - (int) a;
if ( next< 26 && next >= 0)
score[next]++;
}
}
public int largestLength() {
int largest = 0;
int largestindex = 0;
for(int a = 0; a<26; a++) {
if(score[a] > largest) {
largest = score[a];
largestindex = a ;
}
}
return (char) largestindex;
}
public void printResults() {
largestLength();
for (int i = 0; i < score.length; i++) {
System.out.println( (char)(i+97) + ": " + score[i]);
}
System.out.println(("Most Frequent") + (": ") + largestLength());
}
}
A bit of a confusing explanation but any help would be appreciated.
If my string were to be "Hello", l shows up most frequently so i would like it to display, "Most Frequent: l 2" but with my code it displays "Most Frequent: 11" (11 = L). How would I go about fixing this?
Simple: String.valueOf((char)(number + 'A'));
I am trying to solve this, but i don't know how...
Values[10] = {1,1,4,4,2,3,3,2,1,3}
to print:
{1,2,3,4} or {1,4,2,3} (not sorted, any order, but distinct)
I also need to count the number of times each number has occurred, both without sort, new arrays or boolean methods or other data structures, please advise as i am stuck.
Is there a simple method i can use to just print the unique values/ distinct values ?
It can be accomplished if your are willing to destroy your current array. and you assume that the array is either of type Integer (so nullable) or if not there is some bound such as all int are poistive so you can use -1.
for(int i = 0; i < values.length; i++){ //for entire array
Integer currVal = values[i]; // select current value
int count = 1; // and set count to 1
if(currVal != null){ // if value not seen
for( int j = i + 1; j < values.length; j++){ // for rest of array
if(values[j] == currVal){ // if same as current Value
values[j] = null; // mark as seen
count++; // and count it
}
}
System.out.print("Number : " + currVal + " Count : " + count + "\n");
//print information
}
// if seen skip.
}
In plain english, Go through the array in 2 loops, roughly O(n^2) time.
Go to index i. If index has not yet been seen (is not null) then go through the rest of array, mark any indexs with same value as seen (make it null) and increment count varable. At end of loop print value and count. If Index has be seen (is null) skip and go to next index. At end of both loops all values will be left null.
Input : Values[] = {1,1,4,4,2,3,3,2,1,3}
Output : Values[] = {1,null,4,null,2,3,null,null,null,null}
Number : 1 Count : 3
Number : 4 Count : 2
Number : 2 Count : 2
Number : 3 Count : 3
Edit: corrected my mistake in output, pointed out by commenters.
Another solution, without creating additional objects:
Arrays.sort(values);
for(int i = 0; i < values.length; i++) {
if (i == 0 || value[i] != value[i-1]) {
System.out.println(values[i]);
}
}
And the shortest solution I can think of:
Integer[] values = {1,1,4,4,2,3,3,2,1,3};
Set<Integer> set = new HashSet<Integer>();
set.addAll(Arrays.asList(values));
System.out.println(set);
Assuming the values are guaranteed to be integers, you could also do it by incrementing a check value, scan over the array, sum the number of that check value in the array, add it to an accumulator and loop while the accumulator < array.length.
Something like this (untested):
public void checkArray(int[] toCheck) {
int currentNum = 0;
int currentCount = 0;
int totalSeen = 0;
StringBuilder sb = new StringBuilder();
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for(int i=0; i<toCheck.length; i++) {
min = Math.min(toCheck[i], min);
max = Math.max(toCheck[i], max);
}
System.out.print("{ ");
for(currentNum = min; currentNum < max; currentNum++) {
for(int i=0; i<toCheck.length; i++) {
if(toCheck[i] == currentNum) currentCount++;
}
if(currentCount != 0) {
if(currentNum == min) System.out.print(currentCount + "(" +currentCount+ ")");
else System.out.print(", " + currentCount + " (" +currentCount+ ")");
}
totalSeen += currentCount;
currentCount = 0;
}
System.out.println(" }");
}
It should be noted that while this technically fulfills all your requirements, it will be far less efficient than gbtimmon's approach.
If your ints were {1,2,3,150000}, for example, it will needlessly spin over all the values between 4 and 149999.
Edit: added better limits from tbitof's suggestion.
Your question isn't quite clear to me, since it sounds like you want to do these things without creating any additional objects at all. But if it's just about not creating another array, you could use a Map<Integer, Integer>, where the key is the number from your original array, and the value is the count of times you've seen it. Then at the end you can look up the count for all numbers, and print out all the keys by using Map.keyset()
Edit: For example:
Map<Integer,Integer> counts = new HashMap<Integer, Integer>();
for( int i : values ) {
if( counts.containsKey(i) ) {
counts.put(i, counts.get(i) + 1);
} else {
counts.put(i, 1);
}
}
// get the set of unique keys
Set uniqueInts = counts.keyset();