I am creating an output window for a program dealing with matrices. It is supposed to print out the preformed command along with a formatted version of the matrix. But I am having problems with the alignment. I know the String.format works because i have a toString() method that works correctly.
Notice how the second and third rows are not correctly spaced. This is because the 100.00 has completely filled the formatted string where as the 0.00's need extra spaces to fill the string(see toHtml()). I believe this has something to do with the way that the HTML is being displayed but im not sure. My guess is that the spaces behind the zeros are not being displayed properly or are being combined.
Here are the methods involved.
public String toHtml(int dec)
{
String[] colors = {"#C0C0C0","#FFFFFF"};
String f = "%-"+(getLongestValue()+dec+1)+"."+dec+"f";
String res = "";
for(int r = 0;r<rows;r++)
{
for(int c = 0;c<columns;c++)
{
res += "<span style=\"background-color:"+colors[(r+c)%2]+";\">"+String.format(f, contents[r][c])+"</span>";
}
res += "<p>";
}
return res;
}
which creates the HTML text to be displayed. The method getLongestValue() returns the largest length of any number before its decimal place in the array 'contents'.
and
newOutput("New Matrix ["+name+"]<br>"+m.toHtml());
public void newOutput(String s)
{
JLabel l = new JLabel("<html>"+s+"<br></html>");
l.setFont(new Font("Monospaced",1,18));
jPanel1.add(l);
}
which adds the label to the output window
Also, here is the toString() method for reference
public String toString()
{
String f = "%-"+(getLongestValue()+3)+".2f ";
String res = "";
for(int r = 0;r<rows;r++)
{
for(int c = 0;c<columns;c++)
{
res += String.format(f, contents[r][c]);
}
res += "\n";
}
return res;
}
output of the Matrix through toString()
toString Output
A more extreme version
In this case the program should have found that the largest values were -15 or -20 and set the size of the format length to 6( 3 for the length, 2 for the decimal places and 1 for the decimal) but instead it doesnt appear that any of the values, besides the two I mentioned, are following the format.
Here is the output of toString() for the previous example
toString() output
This fixes it, the spaces arent being represented correctly as monospaced
public String toHtml(int dec)
{
String[] colors = {"#C0C0C0","#FFFFFF"};
String f = "%-"+(getLongestValue()+dec+2)+"."+dec+"f";
String res = "";
for(int r = 0;r<rows;r++)
{
for(int c = 0;c<columns;c++)
{
res += "<span style=\"background-color:"+colors[(r+c)%2]+";\">"+
String.format(f, contents[r][c]).replaceAll("\\s", ((char)160)+"")+"</span>";
}
res += "<p>";
}
return res+"";
}
Related
I'm trying to get more familiar with Java lambda, can do some streams and such but still a lot to learn.
Got this simple code using JSONObject and JSONArray (org.json.simple with this exact library and no other because Gson is too easy :P) is there a way to simplify the code with java lambda/streams? (I tried with no luck)
JSONArray jsonArray = (JSONArray) jsonObject.get("someData");
Iterator<JSONObject> iterator = jsonArray.iterator();
double total = 0;
while(iterator.hasNext()) {
JSONObject iteratedJson = iterator.next();
// iteratedJson.get("ip") = "101.99.99.101" example values
String ip = (String) iteratedJson.get("ip");
// Need only first octet
ip = ip.substring(0, ip.indexOf("."));
if (Integer.valueOf(ip) >= 1 && Integer.valueOf(ip) <= 100) {
// Another object inside the array object
JSONObject locationObject = (JSONObject) iteratedJson.get("location");
// Id is int but JSONObject don't let me parse int...
long locationId = (Long) locationObject.get("id");
if (locationId == 8) {
// iteratedJson.get("amount") = "$1,999.10" example values
Number number = NumberFormat.getCurrencyInstance(Locale.US).parse((String)iteratedJson.get("amount"));
// Don't need a lot of precission
total = total + number.doubleValue();
}
}
}
You can do like this:
first of all to extract data from JsonObject I've created a class. this class takes a JosonObject as an argument and extract its values as bellow.
class ExtractData {
Integer ip;
long id;
double amount;
public ExtractData(JSONObject jsonObject) {
this.ip = Integer.valueOf(jsonObject.get("ip").toString().split("\\.")[0]);
this.id = Long.parseLong(((JSONObject) jsonObject.get("location")).get("id").toString());
try {
this.amount = NumberFormat.getCurrencyInstance(Locale.US)
.parse((String) jsonObject.get("amount")).doubleValue();
} catch (ParseException e) {
this.amount = 0d;
}
}
// getter&setter
}
then you can use stream API to calculate the sum of the amount property.
jsonArray.stream()
.map(obj -> new ExtractData((JSONObject) obj))
.filter(predicate)
.mapToDouble(value -> ((ExtractData) value).getAmount())
.sum();
for simplifying I've extracted filter operation.
Predicate<ExtractData> predicate = extractData ->
extractData.getIp()>=1 && extractData.getIp()<=100 && extractData.getId() == 8;
I managed to retrieve the SQLite table with only the first item of the array and put it in the UI's TextView. Couldn't get all the of the array's items. From each of the rest of the columns, a single value is returned successfully.
The JSON is parsed and passed as a parcelable ArrayList to a Fragment where it's presented in a list. Clicking on a list item directs to another Fragment where all the of item's details are presented.
I've been trying to write a for loop that returns the Strings in the array into the TextView, but the condition i < genresList.size() is always false. I tried using a while loop, but it returns only the first item of the list.
Various ways I've found on the internet didn't work.
Thanks.
Parsing and insertion to SQLite
private void parseJsonAndInsertToSQLIte(SQLiteDatabase db) throws JSONException {
// parsing the json
String jsonString = getJsonFileData();
JSONArray moviesArray = new JSONArray(jsonString);
ContentValues insertValues;
for (int i = 0; i < moviesArray.length(); i++) {
JSONObject jsonObject = moviesArray.getJSONObject(i);
String title = jsonObject.getString("title");
String imageUrl = jsonObject.getString("image");
String rating = jsonObject.getString("rating");
String releaseYear = jsonObject.getString("releaseYear");
JSONArray genresArray = jsonObject.getJSONArray("genre");
List<String> genres = new ArrayList<>();
for (int k = 0; k < genresArray.length(); k++) {
genres.add(genresArray.getString(k));
}
insertValues = new ContentValues();
insertValues.put(Movie.TITLE, title);
insertValues.put(Movie.IMAGE_URL, imageUrl);
insertValues.put(Movie.RATING, rating);
insertValues.put(Movie.RELEASE_YEAR, releaseYear);
for (int k = 0; k < genresArray.length(); k++) {
insertValues.put(Movie.GENRE, genres.get(k));
}
Log.i(TAG, "insertValues: " + genresArray);
long res = db.insert(TABLE_NAME, null, insertValues);
Log.i(TAG, "parsed and inserted to sql - row: " + res);
}
}
The item's details Fragment
public class MovieDetailsFragment extends Fragment{
... variables declarations come here...
#Nullable
#Override
public View onCreateView(#NotNull LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_details_movie, container, false);
Context context = getActivity();
Bundle idBundle = getArguments();
if (idBundle != null) {
movieId = getArguments().getInt("id");
}
getDatabase = new GetDatabase(context);
getDatabase.open();
Cursor cursor = getDatabase.getMovieDetails(movieId);
... more irelevant code comes here...
titleView = rootView.findViewById(R.id.movieTtlId);
ratingView = rootView.findViewById(R.id.ratingId);
releaseYearView = rootView.findViewById(R.id.releaseYearId);
genreView = rootView.findViewById(R.id.genreID);
String titleFromSQLite = cursor.getString(cursor.getColumnIndex(Movie.TITLE));
String ratingFromSQLite = cursor.getString(cursor.getColumnIndex(Movie.RATING));
String releaseYearFromSQLite = cursor.getString(cursor.getColumnIndex(Movie.RELEASE_YEAR));
String genreFromSQLite;
if(cursor.moveToFirst()) {
do {
genreFromSQLite = cursor.getString(cursor.getColumnIndex(Movie.GENRE));
genres.add(genreFromSQLite);
} while (cursor.moveToNext());
}
else{
genreFromSQLite = cursor.getString(cursor.getColumnIndex(Movie.RELEASE_YEAR));
}
getDatabase.close();
//more irelevant code comes here
genreView.setText(genreFromSQLite);
genreView.setFocusable(false);
genreView.setClickable(false);
return rootView;
}
}
The method that returns the table from SQLite:
public ArrayList<Movie> getMovies() {
String[] columns = {
Movie.ID,
Movie.TITLE,
Movie.IMAGE_URL,
Movie.RATING,
Movie.RELEASE_YEAR,
Movie.GENRE
};
// sorting orders
String sortOrder =
Movie.RELEASE_YEAR + " ASC";
ArrayList<Movie> moviesList = new ArrayList<>();
Cursor cursor = db.query(TABLE_NAME, //Table to query
columns,
null,
null,
null,
null,
sortOrder);
if (cursor.moveToFirst()) {
do {
Movie movie = new Movie();
movie.setMovieId(Integer.parseInt(cursor.getString(cursor.getColumnIndex(Movie.ID))));
movie.setTitle(cursor.getString(cursor.getColumnIndex(Movie.TITLE)));
movie.setImageUrl(cursor.getString(cursor.getColumnIndex(Movie.IMAGE_URL)));
movie.setRating(cursor.getDouble(cursor.getColumnIndex(Movie.RATING)));
movie.setReleaseYear(cursor.getInt(cursor.getColumnIndex(Movie.RELEASE_YEAR)));
List<String> genreArray = new ArrayList<>();
while(cursor.moveToNext()){
String genre = cursor.getString(cursor.getColumnIndex(Movie.GENRE));
genreArray.add(genre);
}
movie.setGenre(Collections.singletonList(String.valueOf(genreArray)));
// Adding a movie to the list
moviesList.add(movie);
} while (cursor.moveToNext());
}
Log.d(TAG, "The movies list from sqlite: " + moviesList);
cursor.close();
db.close();
return moviesList;
}
I believe your issue is with :-
for (int k = 0; k < genresArray.length(); k++) {
insertValues.put(Movie.GENRE, genres.get(k));
}
That will result in just the last value in the loop being inserted as the key/column name (first parameter of the put) does not change (and probably can't as you only have the one column).
You could use :-
StringBuilder sb = new StringBuilder();
for (int k = 0; k < genresArray.length(); k++) {
if (k > 0) {
sb.append(",");
}
sb.append(genres.get(k));
}
insertValues.put(Movie.GENRE, sb.toString());
Note the above code is in-principle code. It has not been tested or run and may therefore contains errors.
This would insert all the data as a CSV into the GENRE column.
BUT that is not a very good way as far as utilising databases. It would be far better if the Genre's were a separate table and probably that a mapping table were used (but that should be another question).
This is going to cause you issues as well :-
if (cursor.moveToFirst()) {
do {
Movie movie = new Movie();
movie.setMovieId(Integer.parseInt(cursor.getString(cursor.getColumnIndex(Movie.ID))));
movie.setTitle(cursor.getString(cursor.getColumnIndex(Movie.TITLE)));
movie.setImageUrl(cursor.getString(cursor.getColumnIndex(Movie.IMAGE_URL)));
movie.setRating(cursor.getDouble(cursor.getColumnIndex(Movie.RATING)));
movie.setReleaseYear(cursor.getInt(cursor.getColumnIndex(Movie.RELEASE_YEAR)));
List<String> genreArray = new ArrayList<>();
while(cursor.moveToNext()){
String genre = cursor.getString(cursor.getColumnIndex(Movie.GENRE));
genreArray.add(genre);
}
movie.setGenre(Collections.singletonList(String.valueOf(genreArray)));
// Adding a movie to the list
moviesList.add(movie);
} while (cursor.moveToNext());
That is you move to the first row of the Cursor, extract some data MoveieId,Title ... ReleaseYear.
Then
a) if there any other rows you move to the next (which would be for a different Movie) and the next until you finally reached the last row adding elements to the genreArray.
or
b) If there is only the one row in the Cursor genreArray is empty.
You then add the 1 and only movie to the movieList and return.
1 move (row) in the Cursor will exist per movie and there is only the 1 GENRE column per movie. You have to extract the data in that column and then split the data into the genreArray without moving (see the previous fix that will create a CSV (note that would be messed up if the data contained commas)).
IF you used the previous fix and store the multiple genres as a CSV, then you could use :-
if (cursor.moveToFirst()) {
do {
Movie movie = new Movie();
movie.setMovieId(Integer.parseInt(cursor.getString(cursor.getColumnIndex(Movie.ID))));
movie.setTitle(cursor.getString(cursor.getColumnIndex(Movie.TITLE)));
movie.setImageUrl(cursor.getString(cursor.getColumnIndex(Movie.IMAGE_URL)));
movie.setRating(cursor.getDouble(cursor.getColumnIndex(Movie.RATING)));
movie.setReleaseYear(cursor.getInt(cursor.getColumnIndex(Movie.RELEASE_YEAR)));
List<String> genreArray = new List<>(Arrays.asList((cursor.getString(cursor.getColumnIndex(Movie.GENRE))).split(",",0)));
movie.setGenre(Collections.singletonList(String.valueOf(genreArray)));
// Adding a movie to the list
moviesList.add(movie);
} while (cursor.moveToNext());
Note the above code is in-principle code. It has not been tested or run and may therefore contains errors.
I got some formatting issue in ssis. I have some sets of telephone numbers from text files and a hyphen needs to be added with this format.
ex. 1234567890
formatted: 123-456-7890
Im thinking using substring in expression from derived column task. Hope u can help. Thanks!
public static String setHyphen(String str) {
StringBuilder stringBuilder = new StringBuilder();
char ssnArr[] = str.toCharArray();
for(int i=0;i<ssnArr.length;i++){
if(i == 2 || i == 5){
stringBuilder.append(ssnArr[i] + "-");
}else{
stringBuilder.append(ssnArr[i]);
}
}
return stringBuilder.toString();
}
guys i am trying in convert my xml file to csv using hadoop so i am using the following code in mapper class
protected void map(LongWritable key, Text value,
#SuppressWarnings("rawtypes") Mapper.Context context)
throws
IOException, InterruptedException {
String document = value.toString();
System.out.println("‘" + document + "‘");
try {
XMLStreamReader reader =
XMLInputFactory.newInstance().createXMLStreamReader(new
ByteArrayInputStream(document.getBytes()));
String propertyName = "";
String propertyValue = "";
String currentElement = "";
while (reader.hasNext()) {
int code = reader.next();
switch (code) {
case XMLStreamConstants.START_ELEMENT: //START_ELEMENT:
currentElement = reader.getLocalName();
break;
case XMLStreamConstants.CHARACTERS: //CHARACTERS:
if (currentElement.equalsIgnoreCase("author")) {
propertyName += reader.getText();
} else if (currentElement.equalsIgnoreCase("price"))
{
String name=reader.getText();
name.trim();
propertyName += name;
propertyName.trim();
}
}
console.write(null,new Text(propertyName));
}
}
but the output i am getting is in this form
Gambardella, Matthew
XML Developer's Guide
44.95
2000-10-01
Ralls, Kim
Midnight Rain
5.95
2000-12-16
can u help me with this
The output of the program depends on how you are collecting/writing from mapper.
In this case you should be using TextOutputFormat & KeyOut will be NullWritable and ValueOut will be Text. The Value out should be a concatenation of the values which you extracted from CSV.
From your code it looks like you are writing output after reading each value from the XML.
How can I find the permutations of k in a given length?
For example:
The word cat has 3 letters: How can I find all the permutations of 2 in the word cat.
Result should be: ac, at, ca, ac, etc...
This is not a homework problem.
Any language could be used but more preferable: C/C++ or C#.
I know how to create the recursion for size LENGTH but not for a custom size.
Here is one in C#, which should work even with repeated characters. For example on "banana" for permutations of length 2 it gives:
ba bn ab aa an nb na nn
The basic idea is to fix the first character, then form all permutations of length k-1, then prepend the character to those k-1 length permutations. To deal with duplicate characters, we keep track of the count left (i.e the ones which can be used for sub-permutations).
Not exemplary code, but should give you the idea. (If you find bugs, let me know and I can edit).
static List<string> Permutations(Dictionary<char, int> input, int length) {
List<string> permutations = new List<string>();
List<char> chars = new List<char>(input.Keys);
// Base case.
if (length == 0) {
permutations.Add(string.Empty);
return permutations;
}
foreach (char c in chars) {
// There are instances of this character left to use.
if (input[c] > 0) {
// Use one instance up.
input[c]--;
// Find sub-permutations of length length -1.
List<string> subpermutations = Permutations(input, length - 1);
// Give back the instance.
input[c]++;
foreach (string s in subpermutations) {
// Prepend the character to be the first character.
permutations.Add(s.Insert(0,new string(c,1)));
}
}
}
return permutations;
}
And here is the full program I have, to use it:
using System;
using System.Collections.Generic;
namespace StackOverflow {
class Program {
static void Main(string[] args) {
List<string> p = Permutations("abracadabra", 3);
foreach (string s in p) {
Console.WriteLine(s);
}
}
static List<string> Permutations(string s, int length) {
Dictionary<char, int> input = new Dictionary<char, int>();
foreach (char c in s) {
if (input.ContainsKey(c)) {
input[c]++;
} else {
input[c] = 1;
}
}
return Permutations(input, length);
}
static List<string> Permutations(Dictionary<char, int> input,
int length) {
List<string> permutations = new List<string>();
List<char> chars = new List<char>(input.Keys);
if (length == 0) {
permutations.Add(string.Empty);
return permutations;
}
foreach (char c in chars) {
if (input[c] > 0) {
input[c]--;
List<string> subpermutations = Permutations(input,
length - 1);
input[c]++;
foreach (string s in subpermutations) {
permutations.Add(s.Insert(0,new string(c,1)));
}
}
}
return permutations;
}
}
}
What's wrong with the recursive solution and passing an extra parameter (depth) so that the recursive function returns immediately for depth > n.
Not the most efficient, but it works:
public class permutation
{
public static List<string> getPermutations(int n, string word)
{
List<string> tmpPermutation = new List<string>();
if (string.IsNullOrEmpty(word) || n <= 0)
{
tmpPermutation.Add("");
}
else
{
for (int i = 0; i < word.Length; i++)
{
string tmpWord = word.Remove(i, 1);
foreach (var item in getPermutations(n - 1, tmpWord))
{
tmpPermutation.Add(word[i] + item);
}
}
}
return tmpPermutation;
}
}
void Prem (char *str, int k, int length) {
if (k == length-1){
printf("%s\n",str);
return;
} else {
for (int i = k ; i < length; ++i) {
char t = str[k];
str[k] = str[i];
str[i] = t;
Prem(str,k+1,length);
t = str[k];
str[k] = str[i];
str[i] = t;
}
}
}
If I'm not mistaken, this problem can be solved by combinadics too, as on http://en.wikipedia.org/wiki/Combinadic/, there are reference implementations there too.
I have used the Java solution (http://docs.google.com/Doc?id=ddd8c4hm_5fkdr3b/) myself for generating all possible triples from a sequence of numbers, this should be no different.
I lack the wherewithal to explain the math behind it, but as I understand this is the least complex way to iterate over all possible nCr (i.e. 3C2 for your cat example) choices within a collection.
First find the possible subsets of your array. You can do this in
a recursive way it was discussed in Iterating over subsets of any size
Second calculate the permutations of every subset with the STL-Algorithm
next_permutation
I haven't implemented it but i think it should work.