This question already has answers here:
Sort on a string that may contain a number
(24 answers)
Closed 3 years ago.
The output of this string should be sorted as follows.
The output of this string should be sorted as follows.
public static void main(String[] args) {
String input="";
List<String> items = Arrays.asList(input.split("\\s*,\\s*"));
System.out.println("items: " + items);
Collections.sort(items, new Comparator<String>() {
public int compare(String o1, String o2) {
String o1StringPart = o1.replaceAll("\\d", "");
String o2StringPart = o2.replaceAll("\\d", "");
if (o1StringPart.equalsIgnoreCase(o2StringPart)) {
return extractInt(o1) - extractInt(o2);
}
return o1.compareTo(o2);
}
int extractInt(String s) {
String num = s.replaceAll("\\D", "");
// return 0 if no digits found
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
});
for (String s : items) {
System.out.println(s);
}} }
I assume that all the numeric are integer and all the alphabets are A to Z, you can transform those strings which contains / or - into floating points first, then replace all the alphabets to empty strings. Finally, compare their values as Double.
For example, 51/1 will be 51.1 and 571-573B will be 571.573.
Code snippet
public int compare(String o1, String o2) {
String n1 = o1.replace("-", ".").replace("/", ".").replaceAll("[A-Z]", "");
String n2 = o2.replace("-", ".").replace("/", ".").replaceAll("[A-Z]", "");
// This equals above statements
//String n1 = o1.replaceAll("[-/]", ".").replaceAll("[A-Z]", "");
//String n2 = o2.replaceAll("[-/]", ".").replaceAll("[A-Z]", "");
int result = Double.compare(Double.valueOf(n1), Double.valueOf(n2));
return (result == 0) ? o1.compareTo(o2) : result;
}
This is not the most elegant way, but I think it should work!
Use the below snippet code. Firstly, you need to compare the integer part of the string and in case the integer part is equal compare the string part.
import java.io.*;
import java.util.*;
import java.util.regex.*;
/*
* To execute Java, please define "static void main" on a class
* named Solution.
*
* If you need more classes, simply define them inline.
*/
class Solution {
public static void main(String[] args) {
String input = "605,2A,401-2A,32C,21F,201A,605A,401-1A,200-2E,583-58D,583/58E,583-57D,542,2B,1,542/2E,605B,32D,3,603,4,6,5,60,201C,542/2D,40,20,50,200-2C,21C,800A,200A,571-573B,51/2,470/1,51/1,571-573C,454-1,444-446";
List < String > items = Arrays.asList(input.split("\\s*,\\s*"));
System.out.println("items: " + items);
Pattern pattern = Pattern.compile("^\\d+");
Collections.sort(items, new Comparator < String > () {
public int compare(String o1, String o2) {
int intDiff = extractInt(o1) - extractInt(o2);
if (intDiff == 0) {
return o1.compareTo(o2);
}
return intDiff;
}
int extractInt(String s) {
Matcher matcher = pattern.matcher(s);
if (matcher.find()) {
String num = matcher.group(0);
return Integer.parseInt(num);
}
return 0;
}
});
for (String s: items) {
System.out.println(s);
}
}
}
This answer handles comparison between numbers like 20-10A and 20-2A
public static void main(String[] args) {
String s = "605,2A,401-2A,32C,21F,201A,605A,401-1A,200-2E,583-58D,583/58E,583-57D,542,2B,1,542/2E," +
"605B,32D,3,603,4,6,5,60,201C,542/2D,40,20,50,200-2C,21C,800A,200A,571-573B,51/2,470/1,51/1," +
"571-573C,454-1,444-446";
String[] strings = s.split(",");
Arrays.sort(strings, App::compare);
System.out.println(Arrays.deepToString(strings));
}
public static int compare(String o1, String o2) {
if (startsWithDelim(o1)) return compare(o1.substring(1), o2);
if (startsWithDelim(o2)) return compare(o1, o2.substring(1));
List<String> n1 = extractInt(o1);
List<String> n2 = extractInt(o2);
if (n1 != null && n2 != null) {
Integer n1int = Integer.parseInt(n1.get(0));
Integer n2int = Integer.parseInt(n2.get(0));
String n1Remaining = n1.get(1);
String n2Remaining = n2.get(1);
int intCompare = n1int.compareTo(n2int);
return intCompare == 0 ? compare(n1Remaining, n2Remaining) : intCompare;
}
if (n1 == null && n2 == null)
return o1.compareTo(o2);
else if (n1 == null) return -1;
else return 1;
}
static List<String> extractInt(String s) {
Pattern pattern = Pattern.compile("^\\d+");
Matcher matcher = pattern.matcher(s);
if (matcher.find()) {
String num = matcher.group(0);
return List.of(num, s.substring(matcher.end(0)));
}
return null;
}
static boolean startsWithDelim(String s) {
return (s.startsWith("/") || s.startsWith("-"));
}
I will provide some tips
In order compare the items 1,20,200-2C,3,32C,32D,4 (this is the default sort order, as string) you need to check if any number is included in the string. This can be done using a regular expression. You can find a lot of examples online with regular expressions that can bring you the numbers in the string back.
Modify your comparator and check if any of the two string that are to be compared include any number and return the appropriate result.
the extractInt method can be similar to as #Pankaj Saini 's suggestion
Integer extractInt(String s) {
Pattern pattern = Pattern.compile("^\\d+");
Matcher matcher = pattern.matcher(s);
if (matcher.find()) {
String num = matcher.group(0);
return Integer.parseInt(num);
}
return null;
}
The compare method can be like this
public int compare(String o1, String o2) {
if(extractInt(o1)!=null && extractInt(o2)!=null){
if(extractInt(o1).equals(extractInt(o2)))
{
return o1.substring(extractInt(o1).toString().length())
.compareTo(o2.substring(extractInt(o2).toString().length()));
}
return extractInt(o1).compareTo(extractInt(o2));
}
else if(extractInt(o1)!=null)
{
return -1;
}
else if(extractInt(o2)!=null)
{
return 1;
}
else{
return o1.compareTo(o2);
}
}
SORRY ABOUT FORMATTING. i am trying to determine if the grade is a passing, failing, or invalid grade. however i can't figure out how to catch the error.
EDIT: 70-100 OR "s" or "S" = pass; 0-69 OR u or U = retake; everything else = invalid.
This is my code:
import java.util.*;
public class Demo
{
public static void main(String [] args)
{
Scanner kb = new Scanner(System.in);
String total="";
System.out.println("enter grade");
total = kb.nextLine();
System.out.println(evaluateGrade(total));
}
public static String evaluateGrade(String expr)
{
String result ="";
boolean invalid = false;
int grade = Integer.parseInt(expr);
try{
if((grade <100 && grade >=70) || (expr.equalsIgnoreCase("s"))
{
result ="pass";
}
else if((grade <70 && grade >0)|| expr.equalsIgnoreCase("u"))
{
result ="retake";
}
else
{result="invalid";
}
} catch (Exception e)
{
}
return result;
}
}
This is my code:
import java.util.*;
class Demo{
public static void main(String [] args){
Scanner kb = new Scanner(System.in);
System.out.println("enter grade");
System.out.println(evaluateGrade(kb.next()));
kb.close(); // You need to ".close" your stuff
}
public static String evaluateGrade(String expr){
String result ="";
// boolean invalid = false; <--- This is not necessary
if(expr.equalsIgnoreCase("s")){
return "pass";
}
if(expr.equalsIgnoreCase("u")){
return "retake";
}
try{ // Try to get a Integer on "grade"
Integer grade = Integer.valueOf(expr);
if( (grade <= 100 && grade >=70)){ // 70 <= grade <= 100, and you forgot the ')'
result ="pass";
}
else if((grade <70 && grade >=0)){ // 0 <= grade < 70
result ="retake";
}
else{
result="invalid";
}
}
catch(NumberFormatException e){ // If "grade" is not a number, then you have this line
System.err.println("Your grade must be a NUMBER between 0 and 100.");
return "invalid"; // Return something to keep going with your code
}
return result;
}
}
If you're not understanding what is happening with your code, write it down on the paper.
Have a good day!
I have a string like this "105321,102305,321506,0321561,3215658" and i need to split this string by the comma (,) and with a specific length, so if the length of each string part is 15, the splited array must be like:
105321,102305
321506,0321561
3215658
I try several ways but i can't find the right approach to do this
The code that i have gives me an error of index out of range:
private static List<string> SplitThis(char charToSplit, string text, int maxSplit)
{
List<string> output = new List<string>();
string[] firstSplit = text.Split(charToSplit);
for(int i = 0; i < firstSplit.Length; i++)
{
string part = firstSplit[i];
if(output.Any() && output[i].Length + part.Length >= maxSplit)
{
output.Add(part);
}
else
{
if(!output.Any())
output.Add(part);
else
output[i] += "," + part;
}
}
return output;
}
Edit: i must say that the comma , must be a part of the amount of the maxSplit variable.
This one would be concise, yet not really performant
private static Pattern P = Pattern.compile("(.{1,15})(,|$)");
private static String[] split(String string) {
Matcher m = P.matcher(string);
List<String> splits = new ArrayList<String>();
while (m.find()) {
splits.add(m.group(1));
}
return splits.toArray(new String[0]);
}
The regular expression in P matches (.{1,15})(,|$):
a sequence of 1 to 15 characters = .{1,15}
followed by , or line ending
the parentheses allow grouping, the content of the first group is what you are interested in
static void Main(string[] args)
{
string originalString = "105321,102305,321506,0321561,3215658";
string[] commaSplit = originalString.Split(',');
string tempString = string.Empty;
List<string> result = new List<string>();
for (int i = 0; i < commaSplit.Length; i++ )
{
if ((tempString.Length + commaSplit[i].Length) > 15)
{
result.Add(tempString);
tempString = string.Empty;
}
if (tempString.Length > 0)
{
tempString += ',' + commaSplit[i];
}
else
{
tempString += commaSplit[i];
}
if (i == commaSplit.Length - 1 && tempString != string.Empty)
{
result.Add(tempString);
}
}
foreach (var s in result)
{
Console.WriteLine(s);
}
Console.ReadKey();
}
This may not be the best solution but it works ;)
what about this?
private static List<string> SplitThis(char charToSplit, string text, int maxSplit)
{
List<string> output = new List<string>();
string[] firstSplit = text.Split(charToSplit);
int i = 0;
while (i < firstSplit.Length)
{
string part = firstSplit[i];
while (part.Length < maxSplit)
{
if (part.Length < maxSplit && i + 1 < firstSplit.Length)
{
if ((part + "," + firstSplit[i + 1]).Length < maxSplit)
{
part += "," + firstSplit[i + 1];
i++;
}
else
{
output.Add(part);
i++;
break;
}
}
else
{
output.Add(part);
i++;
break;
}
}
}
return output;
}
I am new to TestNG framework. Please guide how to parameterise the test cases using Apache POI(Excel).
I have a code to read from second row from Excel.
public class spreadData {
private transient Collection data = null;
public spreadData(final InputStream excelInputStream) throws IOException {
this.data = loadFromSpreadsheet(excelInputStream);
}
public Collection getData() {
return data;
}
private Collection loadFromSpreadsheet(final InputStream excelFile)
throws IOException {
HSSFWorkbook workbook = new HSSFWorkbook(excelFile);
data = new ArrayList();
Sheet sheet = workbook.getSheetAt(0);
int numberOfColumns = countNonEmptyColumns(sheet);
List rows = new ArrayList();
List rowData = new ArrayList();
/*for (Row row : sheet) {
if (isEmpty(row)) {
break;
} else {
rowData.clear();
for (int column = 0; column < numberOfColumns; column++) {
Cell cell = row.getCell(column);
rowData.add(objectFrom(workbook, cell));
}
rows.add(rowData.toArray());
}
}*/
int rowStart = 1;
//int rowEnd = Math.max(1400, sheet.getLastRowNum());
for (int rowNum = rowStart; rowNum <= sheet.getLastRowNum(); rowNum++) {
//Row r = sheet.getRow(rowNum);
Row read = sheet.getRow(rowNum);
if (isEmpty(read)) {
break;
} else {
rowData.clear();
for (int column = 0; column < numberOfColumns; column++) {
Cell cell = read.getCell(column);
rowData.add(objectFrom(workbook, cell));
}
rows.add(rowData.toArray());
}
}
return rows;
}
private boolean isEmpty(final Row row) {
Cell firstCell = row.getCell(0);
boolean rowIsEmpty = (firstCell == null)
|| (firstCell.getCellType() == Cell.CELL_TYPE_BLANK);
return rowIsEmpty;
}
/**
* Count the number of columns, using the number of non-empty cells in the
* first row.
*/
private int countNonEmptyColumns(final Sheet sheet) {
Row firstRow = sheet.getRow(0);
return firstEmptyCellPosition(firstRow);
}
private int firstEmptyCellPosition(final Row cells) {
int columnCount = 0;
for (Cell cell : cells) {
if (cell.getCellType() == Cell.CELL_TYPE_BLANK) {
break;
}
columnCount++;
}
return columnCount;
}
private Object objectFrom(final HSSFWorkbook workbook, final Cell cell) {
Object cellValue = null;
if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
cellValue = cell.getRichStringCellValue().getString();
} else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
cellValue = getNumericCellValue(cell);
} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
cellValue = cell.getBooleanCellValue();
} else if (cell.getCellType() ==Cell.CELL_TYPE_FORMULA) {
cellValue = evaluateCellFormula(workbook, cell);
}
return cellValue;
}
private Object getNumericCellValue(final Cell cell) {
Object cellValue;
if (DateUtil.isCellDateFormatted(cell)) {
cellValue = new Date(cell.getDateCellValue().getTime());
} else {
cellValue = cell.getNumericCellValue();
}
return cellValue;
}
private Object evaluateCellFormula(final HSSFWorkbook workbook, final Cell cell) {
FormulaEvaluator evaluator = workbook.getCreationHelper()
.createFormulaEvaluator();
CellValue cellValue = evaluator.evaluate(cell);
Object result = null;
if (cellValue.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
result = cellValue.getBooleanValue();
} else if (cellValue.getCellType() == Cell.CELL_TYPE_NUMERIC) {
result = cellValue.getNumberValue();
} else if (cellValue.getCellType() == Cell.CELL_TYPE_STRING) {
result = cellValue.getStringValue();
}
return result;
}
}
My question is how to parameterise the test cases using TestNG? means by using #DataProvider TestNG annotation.
Kindly help me with a sample code or explanation.
I'm not sure which set of data you want...but here's how a dataProvider works:
Say I have a test that takes a String and then an int like this:
#Test(dataProvider = "excelData")
public void executeTest(String name, int value){}
My data provider would look something like this:
#DataProvider(name = "excelData")
public Object[][] data(){
return new Object[][]{
{"Test",1},
{"More Testing",7},
{"Last Test",-5}}
}
The test will be run 3 times, with each row of the array is the set of data that is to be passed in. You will need to convert your excel data into such a format.
Note, you can also return an Iterator<Object[]> if you prefer.
I have an array with 5 elements. If a user inputs a name or a title, it should output that person's or job title's corresponding job title and person. Here's what I got, I'm not sure what I could be doing wrong. Since it's an applet, I don't need a main method right? Did I get stuff mixed up? What could I be doing wrong? Even if I input data that is stored in the array, it always gives me "input did not match any records" I would appreciate any help. Thanks in advance!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Assignment extends JApplet implements ActionListener
{
String[] empName = {"John Jacobs" , "Will Watts","Kevin Krust", "Allan Ayers", "Sam Smith"};
String[] empTitle = {"Software Engineer" , "Database Administrator", "Network Administrator" , "Head Programmer" ,"Department Manager"};
final int ARRAY_SIZE = 5;
boolean validName = false;
boolean validTitle = false;
String nameOfEmployee;
String titleOfEmployee;
JLabel enterInfo = new JLabel("Enter an Employee Name or Job Title");
JTextField userInput = new JTextField(20);
JButton empButton = new JButton ("Press if you entered a name");
JButton titleButton = new JButton ("Press if you entered a title");
JLabel inputDisplay = new JLabel("");
Container con = getContentPane();
public void init()
{
con.add(enterInfo);
con.add(userInput);
con.add(empButton);
con.add(titleButton);
con.setLayout(new FlowLayout());
userInput.addActionListener(this);
empButton.addActionListener(this);
titleButton.addActionListener(this);
}
public void actionPerformed(ActionEvent event)
{
Object source = event.getSource();
if (source == empButton)
{
String nameEmp = userInput.getText();
con.remove(enterInfo);
con.remove(userInput);
con.remove(empButton);
con.remove(titleButton);
for (int x = 0; x < ARRAY_SIZE; ++x)
{
if (nameEmp == empName[x])
{
validName = true;
titleOfEmployee = empTitle[x];
}
}
if(validName)
inputDisplay.setText(nameEmp + "is a" + titleOfEmployee);
else
inputDisplay.setText("The title you input did not match any records.");
con.add(inputDisplay);
con.setBackground(Color.YELLOW);
}
else
{
String nameJob = userInput.getText();
con.remove(enterInfo);
con.remove(userInput);
con.remove(empButton);
con.remove(titleButton);
for (int x = 0; x < ARRAY_SIZE; ++x)
{
if (nameJob == empTitle[x])
{
validTitle = true;
nameOfEmployee = empName[x];
}
}
if(validName)
inputDisplay.setText(nameOfEmployee + "is a" + nameJob);
else
inputDisplay.setText("The name you input did not match any records.");
con.add(inputDisplay);
con.setBackground(Color.YELLOW);
}
con.invalidate();
con.validate();
}
}
This
nameEmp == empName[x]
compares object references. What you want is comparison of contents, so you should check
nameEmp.equals(empName[x])
When comparing the value input by the user to the values in your arrays, you need to use the equals function and not ==.
Read why here.