Side by side tables java - java

I am new and have a question that is dumbfounding me.
I'm doing a conversion table where it is side by side miles to kilometers, a similar question that was never fully answered in 3 years. now i'm only using print(f)(ln) format, no Jtables, nada, simple println.
I got the table to be side by side using for loops but ran into a problem on the output that is kicking my keester.
The output I get is repeating itself 10 times here:
1 1.609 | 20 32.18
2 1.609 | 21 33.789
3 1.609 | 22 35.397
so I used an if statment and %5 == 0 in my for loop and I got this output:
1 1.609 | 20 32.18
2 1.609 | 25 40.225
3 1.609 | 30 48.269
So now i try a break statement, and i get this:
1 1.609 | 20 32.18
2 3.218 | 20 32.18
3 4.768 | 20 32.18
I run into dead code in my second loop but it cuts off at 10 like it should in the right table but dead code in the left so I use a continue statement and get this:
1 1.609 | 20 32.18
2 1.609 | 25 40.225
3 1.609 | 30 48.269
My final correct result should be:
1 1.609 | 20 32.18
2 3.218 | 25 40.225
3 4.768 | 30 48.269
... so on till 10.
Could anybody give me a clue as to how to fix this, I dont want the answer just a little help. Thank you
Edit: how do i make my code output vertical and not horozantal so it is easier to read?

You don't need a nested loop, one for-loop will do the job
int x = 1.609;
int k = 20;
for (int i=1; i<=10; i++) {
System.out.println(i + " " + i*x + " | " + k + " " + k*x);
k+=5;
}

Related

Convert a double list to a grouped string

The program has an input a list of doubles and the output needs to be a string containing the list values grouped by their value. The list values will be grouped if they are equal.
Something like:
input 9,77,5,5,31 => output 9 77 2*5 31
I created an algorithm in C# (in Java I think that is almost the same) for this but I am not sure if it can be improved regarding its speed or code quaility, or if it has some bugs that I could not see. The algorithm having also some more input, output examples is below.
List<double> input = new List<double> { 11, 32, 32, 43}; // output 11 2*32 43
//List<double> input = new List<double> { 11, 11, 43, 43 }; // output 2*11 2*43
//List<double> input = new List<double> { 10, 11, 12, 13, 14, 15, 16 }; // output 10 11 12 13 14 15 16
//List<double> input = new List<double> { 11, 11, 11, 11, 11 }; // output 5 * 11
//List<double> input = new List<double> { 11, 11, 32, 22, 22, 22, 4, 10, 10 }; // output 2*11 32 3*22 4 2*10
string listAsString = string.Empty;
double nextElem = double.MinValue;
for (int i = 0; i < input.Count; i++)
{
double currentElem = input[i];
if (i + 1 < input.Count)
{
nextElem = input[i + 1];
}
int equalCount = 0;
while (currentElem.Equals(nextElem) && i < input.Count)
{
equalCount++;
i++;
currentElem = nextElem;
if (i < input.Count)
{
nextElem = input[i];
}
}
if (equalCount < 2)
{
listAsString += currentElem + " ";
}
else
{
listAsString += equalCount + "*" + currentElem + " ";
i--;
}
}
Console.WriteLine(listAsString);
Please let me know if you noticed some bugs or see some improvements that can be done.
Also if you know another implementation of this requirement please add it so that a comparation regarding results, speed, code quality between the algorithms can be done... and find the best way to handle this.
Since the requirement is to group only consecutive equal values, the Dictionary and LINQ GroupBy approaches mentioned in another answer do not apply because they will produce incorrect result for input sequence like 1,2,1. Also there is no standard LINQ method for doing such grouping (except eventually Aggregate method, but it's no more than inefficient for / foreach loop equivalent).
Shortly, your algorithm is the best for such task. But implementation is not.
The main bottleneck is the string concatenation as mentioned by Peroxy, which (also mentioned in the other answer) is easily fixable by utilizing the StringBuilder class. Once you do that, the performance will be just fine.
The other issue I see in the implementation is usage of special values (double.MinValue), duplicate corner case checks, decrementing for loop variable inside the body etc. So although it probably works and I don't see directly a bug, it's kind of hard to follow the algorithm logic and spot a potential bug just reading the implementation. The algorithm itself is quite simple, I would implement it this way:
static string ListAsString(List<double> input)
{
var sb = new StringBuilder();
for (int i = 0; i < input.Count; )
{
var value = input[i];
int count = 1;
while (++i < input.Count && input[i] == value)
count++;
if (sb.Length > 0) sb.Append(' ');
if (count > 1) sb.Append(count).Append('*');
sb.Append(value);
}
return sb.ToString();
}
which IMO is quite easier to follow. Note that there is no duplicate code, no special values and the loop variable i advancing is done only in one place inside the outer loop body. Again, this has nothing to do with performance (which is provided by the StringBuilder usage), but simply readability, redundancy elimination and less error prone.
Personally, I see great potential with Dictionary usage here, here is a quick solution I made with a dictionary implementation:
var input = new List<double> { 9, 77, 5, 5, 31 };
var dict = new Dictionary<double, int>();
var listAsString = new StringBuilder();
foreach (var item in input)
{
if (dict.ContainsKey(item))
dict[item]++;
else
dict[item] = 1;
}
foreach (var item in dict)
{
listAsString.Append(item.Value > 1 ? $"{item.Value}*{item.Key} " : $"{item.Key} ");
}
Console.WriteLine(listAsString);
If you ever wanted a non efficient LINQ one liner solution:
string result = string.Join(" ", input.GroupBy(i => i)
.Select(x =>
x.Count() > 1 ?
$"{x.Count()}*{x.Key} " :
$"{x.Key} "));
However, I believe your method is written nicely, albeit a bit less readable than the dictionary one, but the main flaw with your solution is that you are using a string when building the final string, you should definitely be using a StringBuilder, I have introduced the StringBuilder in your method and made comparisons between these three methods:
Dictionary | Your method | GroupBy method
------------------------------------------------
2 ms | 0 ms | 5 ms n=3
0 ms | 0 ms | 0 ms n=6
0 ms | 0 ms | 0 ms n=12
0 ms | 0 ms | 0 ms n=24
0 ms | 0 ms | 0 ms n=48
0 ms | 0 ms | 0 ms n=96
0 ms | 0 ms | 0 ms n=192
0 ms | 0 ms | 0 ms n=384
0 ms | 0 ms | 0 ms n=768
0 ms | 0 ms | 0 ms n=1536
1 ms | 0 ms | 1 ms n=3072
3 ms | 2 ms | 3 ms n=6144
5 ms | 4 ms | 6 ms n=12288
8 ms | 7 ms | 14 ms n=24576
14 ms | 13 ms | 25 ms n=49152
31 ms | 32 ms | 66 ms n=98304
80 ms | 59 ms | 146 ms n=196608
149 ms | 123 ms | 294 ms n=393216
246 ms | 218 ms | 504 ms n=786432
483 ms | 428 ms | 1040 ms n=1572864
999 ms | 873 ms | 2070 ms n=3145728
1995 ms | 1784 ms | 3950 ms n=6291456
Your solution is always the fastest, if you want to go for speed, keep your solution, but change it to use StringBuilder, use listAsString.Append(currentElem + " ") instead of listAsString += currentElem + " ".
GroupBy could be used if you will only operate with collections that have n < 1000, use the Dictionary solution if you would rather settle with readability over speed.

Generating integers of form 2^n - 1 with for loop

I have an assignment that asks me to write a for loop inside a method that will output this sequence:
1 3 7 15 31 ... 255
I know that the pattern is to multiply the number by two then add one (or just to add the exponents of 2 to each number so 1 + 2 = 3 + 4 = 7 + 8 = 15 etc.) but I don't know how exactly to make a loop that'll output that sequence all the way up to 255.
I would just like an example or explanation to guide me a little bit, I don't want anyone to actually give me the exact code I need. Here's what I've done so far:
public static void methodOne() {
for (int j = 1; j <= 255; j *= 2) {
}
}
I tried to use another for loop within the for loop above but it didn't work well, and I'm not sure if that's the right thing to do. I basically want to take j and have it multiplied by two and then add 1 to get the next number in the sequence.
As you noted, the sequence is to double the previous number and add one. Just have your for loop progress like that, and print the number in each iteration:
for (int j = 1; j <= 255; j = (j * 2) + 1) {
System.out.println(j);
}
As is howework, will leave you something to think:
for x in 2:8 range
result = 2^x -1
this is the most succinct form I could think of that uses only additions ( + ) over 1 single tracking variable:
jot 100 |
mawk '$++NF = _+=_++' CONVFMT='%.f' # mawk-1
gawk '$++NF = _+=_++' # gawk, mawk-2, nawk, etc
1 1
2 3
3 7
4 15
5 31
6 63
7 127
8 255
9 511
10 1023
11 2047
12 4095
13 8191
14 16383
15 32767
16 65535
17 131071
18 262143
. . .
30 1073741823
31 2147483647
32 4294967295
33 8589934591
34 17179869183
35 34359738367
36 68719476735
if you wanna go all the way to 2^1023 - 1 without using a big-int library (tested and confirmed working for mawk-1, mawk-2, gawk 5.2.0, and nawk):
jot 1023 |
mawk '$++NF = (((___+=___++)%((_+=_^=_<_)+_*_*_)^_^_)%_ ||
index(___,"e") < (length(___) < _^_^_--)) \
? ___ : sprintf("%.*s%d", -_+(__ = length(_=\
sprintf("%.f",___))),_,substr(_,__)-!!__)' \
CONVFMT='%.16g'
31 2147483647
279 9713344461128645354597309534117594533212034195260697606259062048
69452142602604249087
527 4393470502483590217588416511412091659052438592091715462012456613
8787476373744998733584381700233309151854696392905477491437580723
1981865204004737810631363657727
775 1987223158144907436990693745232003270728814101909371662257986608
6733452194385624145035243633006674917766242952923277737038996224
5646696242104868771205271185818170236930668787910433956560844600
937633663896795708000114284397288455405567
1023 8988465674311579538646525953945123668089884894711532863671504057
8866337902750481566354238661203768010560056939935696678829394884
4072083112464237153197370621888839467124327426381511098006230470
5972654147604250288441907534117123144073695655527041361858167525
5342293149119973622969239858152417678164812112068607

Using nested for loops to print numbers (java)

I am trying to use nested for loops (java) to print out the following:
331
330
322
311
300
222
111
and I am having some trouble. So far I have:
for(int a = 3; a >=0; a--)
{
for(int b = 3; b>=0; b--)
{
for(int c = 2; c>=0; c--)
{
System.out.println(a + " "+ b +" "+ c);
}
}
}
but that prints out something more like this:
3 3 2
3 3 1
3 3 0
3 2 2
3 2 1
3 2 0
3 1 2
3 1 1
3 1 0
3 0 2
3 0 1
3 0 0
2 3 2
2 3 1
2 3 0
2 2 2
2 2 1
2 2 0
2 1 2
What is wrong with my code? How can I get it to print out the first sequence, not the second? I'm pretty sure it has something to do with the middle loop, but I'm really not sure.
Thanks!
If you have nested for loops, unless you set the limits on the inner loops based on the values of the variables in the outer loops, the pattern generated by the inner loops (second and third numbers, in this case) is gonna be the same in each iteration of the outer loop.
I can't code right now, but it seems to me that if you set b to run from a to zero, instead of from 3 to zero you might get a little closer to what you want.
But still, since it seems there isn't a pattern in what you want to get, it's hard to think of an algorithm to print them. What do these numbers mean?

iterating list with x blocks and pick out y elements out of each block

I do not have a smart or at least working idea how to solve following challenge:
I have 198 assignments and let each assignment solved by 10 persons, then I wrote everything in a PostgreSQL database by using Java hibernate & persistence API. That worked fine so far.
Sometimes I do have 10 different/distinct answers for an assignment - for other assignments I do have only 2 or 3 different/distinct answers (e.g. for the assignment "what is 5 + 5", 8 persons told "10" and 2 persons told "25")
Now I run a SQL statement to get a list with my assignments and the distinct answers:
SELECT DISTINCT question, answer FROM survey INNER JOIN results ON results.survey_id=results.id;
what I get now is a result list that looks more or less like this:
+---------+----------+--------+
| ID | Question | Answer |
+---------+----------+--------+
| 1 | Q1 | 20 |
| 2 | Q1 | 22 |
| 3 | Q1 | 25 |
| 4 | Q1 | 21 |
| 5 | Q1 | 22 |
| 6 | Q1 | 10 |
| 7 | Q1 | 20.5 |
| 8 | Q1 | 22.3 |
| 9 | Q1 | 28 |
| 10 | Q1 | 26 |
| 11 | Q2 | 52 |
| 12 | Q2 | 51 |
| 13 | Q3 | 78 |
| 14 | Q3 | 80 |
| ... | ... | ... |
| ... | ... | ... |
| ... | ... | ... |
+---------+---------+---------+
now the challening part:
I want now randomly pick out 4 distinct answers (if possible) from each assignment (Q1, Q2, Q3, ...) and create a new assignment where people have to vote on the best answer.
But as shown, sometimes I do have less then 4 distinct answers for an assignment. In this case I want to take everything that's available.
How could I iterate through my list and perform this kind of "picking"?
P.S. it's not very important to pick the answers randomly - would also be okay to pick the first 4 answers.
appreciate your help
regards
if the resultset is that small i would just
// if random is needed [see here][1] to adapt the criteria
var answers = session.createCriteria(Answer.class)
.setFetchMode("Question", FetchMode.eager)
.list<Answer>();
// map of orginal question to voting question
Map<Question, Question> questions = new Hashmap<Question, Question>();
for (Answer answer : answers)
{
if (questions.ContainsKey(answer.getQuestion()))
{
Question votingQuestion = questions.get(answer.getQuestion());
if (votingQuestion.getPossibleAnswers().Count() < 4)
votingQuestion.getPossibleAnswers().add(answer.Text);
}
else
{
Question votingQuestion = createVotingQuestion(answer.getQuestion());
votingQuestion.getPossibleAnswers().add(answer.Text);
questions.add(answer.getQuestion(), votingQuestion);
}
}

How do I get the median/mode/range of a column in SQL using Java?

I have to get the median, mode and range of test scores from one column in a table but I am unsure how to go about doing that. When you connect to the database using java, you are normally returned a ResultSet that you can make a table or something out of but how do you get particular numbers or digits? Is there an SQL command to get the median/mode/range or will I have to calculate this myself, and how do you pull out numbers from the table in order to be able to calculate the mode/median/range?
Thanks.
This must be doable in pure SQL. Range is easy with MIN() and MAX() functions. For the remnant, I am no statistics expert, so I can't tell from head, but I found a link which may be of use: http://www.freeopenbook.com/mysqlcookbook/mysqlckbk-chp-13-sect-2.html
13.2 Calculating Descriptive Statistics
13.2.1 Problem
You want to characterize a dataset by computing general descriptive or summary statistics.
13.2.2 Solution
Many common descriptive statistics, such as mean and standard deviation, can be obtained by applying aggregate functions to your data. Others, such as median or mode, can be calculated based on counting queries.
13.2.3 Discussion
Suppose you have a table testscore containing observations representing subject ID, age, sex, and test score:
mysql> SELECT subject, age, sex, score FROM testscore ORDER BY subject;
+---------+-----+-----+-------+
| subject | age | sex | score |
+---------+-----+-----+-------+
| 1 | 5 | M | 5 |
| 2 | 5 | M | 4 |
| 3 | 5 | F | 6 |
| 4 | 5 | F | 7 |
| 5 | 6 | M | 8 |
| 6 | 6 | M | 9 |
| 7 | 6 | F | 4 |
| 8 | 6 | F | 6 |
| 9 | 7 | M | 8 |
| 10 | 7 | M | 6 |
| 11 | 7 | F | 9 |
| 12 | 7 | F | 7 |
| 13 | 8 | M | 9 |
| 14 | 8 | M | 6 |
| 15 | 8 | F | 7 |
| 16 | 8 | F | 10 |
| 17 | 9 | M | 9 |
| 18 | 9 | M | 7 |
| 19 | 9 | F | 10 |
| 20 | 9 | F | 9 |
+---------+-----+-----+-------+
A good first step in analyzing a set of observations is to generate some descriptive statistics that summarize their general characteristics as a whole. Common statistical values of this kind include:
The number of observations, their sum, and their range (minimum and maximum)
Measures of central tendency, such as mean, median, and mode
Measures of variation, such as standard deviation or variance
Aside from the median and mode, all of these can be calculated easily by invoking aggregate functions:
mysql> SELECT COUNT(score) AS n,
-> SUM(score) AS sum,
-> MIN(score) AS minimum,
-> MAX(score) AS maximum,
-> AVG(score) AS mean,
-> STD(score) AS 'std. dev.'
-> FROM testscore;
+----+------+---------+---------+--------+-----------+
| n | sum | minimum | maximum | mean | std. dev. |
+----+------+---------+---------+--------+-----------+
| 20 | 146 | 4 | 10 | 7.3000 | 1.7916 |
+----+------+---------+---------+--------+-----------+
The aggregate functions as used in this query count only non-NULL observations. If you use NULL to represent missing values,you may want to perform an additional characterization to assess the extent to which values are missing. (See Recipe 13.5.)
Variance is not shown in the query, and MySQL has no function for calculating it. However, variance is just the square of the standard deviation, so it's easily computed like this:
STD(score) * STD(score)
STDDEV( ) is a synonym for STD( ).
Standard deviation can be used to identify outliers—values that are uncharacteristically far from the mean. For example, to select values that lie more than three standard deviations from the mean, you can do something like this:
SELECT #mean := AVG(score), #std := STD(score) FROM testscore;
SELECT score FROM testscore WHERE ABS(score-#mean) > #std * 3;
For a set of n values, the standard deviation produced by STD( ) is based on n degrees of freedom. This is equivalent to computing the standard deviation "by hand" as follows (#ss represents the sum of squares):
mysql> SELECT
-> #n := COUNT(score),
-> #sum := SUM(score),
-> #ss := SUM(score*score)
-> FROM testscore;
mysql> SELECT #var := ((#n * #ss) - (#sum * #sum)) / (#n * #n);
mysql> SELECT SQRT(#var);
+------------+
| SQRT(#var) |
+------------+
| 1.791647 |
+------------+
To calculate a standard deviation based on n-1 degrees of freedom instead, do it like this:
mysql> SELECT
-> #n := COUNT(score),
-> #sum := SUM(score),
-> #ss := SUM(score*score)
-> FROM testscore;
mysql> SELECT #var := ((#n * #ss) - (#sum * #sum)) / (#n * (#n - 1));
mysql> SELECT SQRT(#var);
+------------+
| SQRT(#var) |
+------------+
| 1.838191 |
+------------+
Or, more simply, like this:
mysql> SELECT #n := COUNT(score) FROM testscore;
mysql> SELECT STD(score)*SQRT(#n/(#n-1)) FROM testscore;
+----------------------------+
| STD(score)*SQRT(#n/(#n-1)) |
+----------------------------+
| 1.838191 |
+----------------------------+
MySQL has no built-in function for computing the mode or median of a set of values, but you can compute them yourself. The mode is the value that occurs most frequently. To determine what it is, count each value and see which one is most common:
mysql> SELECT score, COUNT(score) AS count
-> FROM testscore GROUP BY score ORDER BY count DESC;
+-------+-------+
| score | count |
+-------+-------+
| 9 | 5 |
| 6 | 4 |
| 7 | 4 |
| 4 | 2 |
| 8 | 2 |
| 10 | 2 |
| 5 | 1 |
+-------+-------+
In this case, 9 is the modal score value.
The median of a set of ordered values can be calculated like this:
If the number of values is odd, the median is the middle value.
If the number of values is even, the median is the average of the two middle values.
Note that the definition of median given here isn't fully general; it doesn't address what to do if there's duplication of the middle values in the dataset.
Based on that definition, use the following procedure to determine the median of a set of observations stored in the database:
Issue a query to count the number of observations. From the count, you can determine whether the median calculation requires one or two values, and what their indexes are within the ordered set of observations.
Issue a query that includes an ORDER BY clause to sort the observations, and a LIMIT clause to pull out the middle value or values.
Take the average of the selected value or values.
For example, if a table t contains a score column with 37 values (an odd number), you need to select a single value, using a query like this:
SELECT score FROM t ORDER BY 1 LIMIT 18,1
If the column contains 38 values (an even number), the query becomes:
SELECT score FROM t ORDER BY 1 LIMIT 18,2
Then you can select the value or values returned by the query and compute the median from their average.
The following Perl function implements a median calculation. It takes a database handle and the names of the table and column that contain the set of observations, then generates the query that retrieves the relevant values, and returns their average:
sub median
{
my ($dbh, $tbl_name, $col_name) = #_;
my ($count, $limit);
$count = $dbh->selectrow_array ("SELECT COUNT($col_name) FROM $tbl_name");
return undef unless $count > 0;
if ($count % 2 == 1) # odd number of values; select middle value
{
$limit = sprintf ("LIMIT %d,1", ($count-1)/2);
}
else # even number of values; select middle two values
{
$limit = sprintf ("LIMIT %d,2", $count/2 - 1);
}
my $sth = $dbh->prepare (
"SELECT $col_name FROM $tbl_name ORDER BY 1 $limit");
$sth->execute ( );
my ($n, $sum) = (0, 0);
while (my $ref = $sth->fetchrow_arrayref ( ))
{
++$n;
$sum += $ref->[0];
}
return ($sum / $n);
}
The preceding technique works for a set of values stored in the database. If you happen to have already fetched an ordered set of values into an array #val, you can compute the median like this instead:
if (#val == 0) # if array is empty, median is undefined
{
$median = undef;
}
elsif (#val % 2 == 1) # if array size is odd, median is middle number
{
$median = $val[(#val-1)/2];
}
else # array size is even; median is average
{ # of two middle numbers
$median = ($val[#val/2 - 1] + $val[#val/2]) / 2;
}
The code works for arrays that have an initial subscript of 0; for languages that used 1-based array indexes, adjust the algorithm accordingly.
I calculate the Trimmed/Truncated mean in SQL Server like this:
with tempResultSet as (
select Score,
ntile(20) over(order by Score) as n,
count(*) over() as x
from #TestScores
)
select avg(cast(Score as float))
from tempResultSet
where (x >= 20 and n between 2 and 19)
or (x < 20 and n between 2 and x - 1)
this removes the upper and lower 10% of your set and get the average of 'Score'
You don't tell us what database you are using so I assume that you want a solution that will work across standard SQL DBMS's.
You can use SQL to calculate range (using the aggregate functions MIN/MAX) and the mean (using AVG) in a simple aggregate.
Standard SQL doesn't support Median so what you need to do is get SQL to sort the output and go through the items till you find the 'middle' one.
Mode is not supported but note that you can use COUNT() and GROUP BY to get SQL to create a frequency listing (how many times each data point appears), the entry with the highest count is the mode.

Categories