Tried writing a sort method where input was given like a string of comma-delimited years and year ranges String input = '2017, 2018,2020-2023,1800-1700,2020,20a9,19z5-1990,2025,20261,2013';
Expectation is to get a string of comma-delimited years and year ranges,and remove all duplicates and invalid inputs.
Below is class written which is not giving me correct output
public class sortYearAndYearRangesString {
public static List<String> sortSpecialString(String input) {
system.debug(input);
List<String> inputList = input.split('');
system.debug(inputList);
Map<Integer,String> stringMap = new Map<Integer,String>();
system.debug(stringMap);
List<String> output = new List<String>();
for (Integer i=0; i<inputList.size(); i++) {
String charac = inputList[i];
if(!charac.isAlphaNumeric()) {
system.debug(charac);
stringMap.put(i,charac);
}else {
output.add(charac);
system.debug(output);
}
}
String finalString = String.join(output,'');
system.debug(finalString);
List<String> resultList = finalString.reverse().split('');
for( Integer I : stringMap.keySet() ){
system.debug(I);
resultList.add(I,stringMap.get(I));
system.debug(resultList);
}
return resultList;
}
Tried validating the solution in Anonymous Apex but no success
public static void validateSolution() {
String input = '2017, 2018,2020-2023,1800-1700,2020,20a9,19z5-1990,2025,20261,2013';
List<Integer> expected = new List<Integer> {2013,2017,2018,2020,2021,2022,2023,2025};
List<Integer> actual = sortYearAndYearRangesString(input);
System.assertEquals(expected, actual, 'Invalid Results');
}
}
Your help is appreciated
Regards
Carolyn
According to your test case, you should also define at least a constant for a maximum value, in order to exclude 20261. Probably you need a minimum too.
I used 1700 as min and 4000 as max because these are the limits for a Date or Datatime field: docs
Moreover the method must return a List<Integer> instead of a List<String>.
You don't need a Map, just a Set would work.
public class SortYearAndYearRangesString {
private static final Integer MAX_YEAR = 4000;
private static final Integer MIN_YEAR = 1700;
public static List<Integer> sortSpecialString(String input) {
Set<Integer> output = new Set<Integer>();
List<String> yearsList = input.split(',');
for (String yearString : yearsList) {
yearString = yearString.trim();
if (yearString.isNumeric()) {
try {
Integer year = Integer.valueOf(yearString);
if (year >= MIN_YEAR && year <= MAX_YEAR) {
output.add(year);
}
} catch (TypeException e) {
System.debug(e.getMessage());
}
} else {
List<String> range = yearString.split('-');
if (range.size() == 2 && range[0].isNumeric() && range[1].isNumeric()) {
try {
// Modify the following two lines once you know how to handle range like 1300-1500 or 3950-4150
Integer firstYear = Math.max(Integer.valueOf(range[0]), MIN_YEAR);
Integer lastYear = Math.min(Integer.valueOf(range[1]), MAX_YEAR);
while (firstYear <= lastYear) {
output.add(firstYear++);
}
} catch (TypeException e) {
System.debug(e.getMessage());
}
}
}
}
List<Integer> sortedYears = new List<Integer>(output);
sortedYears.sort();
return sortedYears;
}
}
If a range that exceed the boundaries (like 1300-1500 or 3950-4150) should be treated as invalid and skipped, please change these lines
Integer firstYear = Math.max(Integer.valueOf(range[0]), MIN_YEAR);
Integer lastYear = Math.min(Integer.valueOf(range[1]), MAX_YEAR);
while (firstYear <= lastYear) {
output.add(firstYear++);
}
as follow:
Integer firstYear = Integer.valueOf(range[0]);
Integer lastYear = Integer.valueOf(range[1]);
if (firstYear >= MIN_YEAR && lastYear <= MAX_YEAR) {
while (firstYear <= lastYear) {
output.add(firstYear++);
}
}
I tested it in anonymous console with the following code:
String input = '2017, 2018,2020-2023,1800-1700,2020,20a9,19z5-1990,2025,20261,2013';
List<Integer> expected = new List<Integer> {2013,2017,2018,2020,2021,2022,2023,2025};
List<Integer> actual = SortYearAndYearRangesString.sortSpecialString(input);
System.debug(actual);
System.assertEquals(expected, actual, 'Invalid Results');
input = '1500,2017, 2018,2020-2023,1800-1700,2020,20a9,19z5-1990,2025,20261,2013,3998-4002';
expected = new List<Integer> {2013,2017,2018,2020,2021,2022,2023,2025,3998,3999,4000};
actual = SortYearAndYearRangesString.sortSpecialString(input);
System.assertEquals(expected, actual, 'Invalid Results');
I made some changes to the class.
It does increment all ranges - and doesn't check if they're years that would make sense. You'll need to add that logic in there (e.g. 1500-1600 would return all years between 1500-1600. Prob best to cap at 1900 or something)
public class SortYearAndYearRangesString{
public static List<Integer> sortSpecialString(String input){
List<String> inputList = input.split(',');
Set<Integer> output = new Set<Integer>();
system.debug('input ' + input);
system.debug('inputList ' + inputList);
for (String s : inputList){
Set<Integer> tempSet = new Set<Integer>();
s.remove(' ');
if (s.contains('-')){
//// break the ranges and fill in years
List<String> tempSet2 = s.split('-');
for (String s2 : tempSet2){
try{
///capture valid integers
Integer tempInt = Integer.valueOf(s2);
tempSet.add(tempInt);
} catch (Exception e){
tempSet.clear();
break;
}
}
System.debug('set ' + tempSet);
if (tempSet.size() > 1){
List<Integer> tempList = new List<Integer>(tempSet);
tempList.sort ();
Integer r = tempList.size() - 1;
// iterate through the years
for (Integer i = tempList.get(0); i < tempList.get(r); i++){
tempSet.add(i) ;
}
}
} else{
try{
///capture valid integers
Integer tempInt = Integer.valueOf(s);
tempSet.add(tempInt);
} catch (Exception e){
continue;
}
}
output.addAll(tempSet);
}
// output is currently set of ints, need to convert to list of integer
List<Integer> finalOutput = new List<Integer>(output);
finalOutput.sort ();
System.debug('finalOutput :' + finalOutput);
return finalOutput;
}}
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);
}
}
I'm trying to make getArrayStringLongerThan() constructor that returns a StringBuffer array with COPIES of StringBuffer objects in the array parameter that have a length greater than the length parameter. If no strings are found an empty array will be returned. Down blew is all I got so far!
public static StringBuffer getArrayStrignsLongerThan(java.lang.StringBuffer[]
array, int length) {
if (array == null || array.length == 0) {
return null;
}
int size = 0;
for (int i = 0; i < array.length + 1; i++) {
size++;
}
// String str="";
StringBuffer buffers[] = new StringBuffer[array.length];
int[] newArray2 = new int[size];
for (int i = 0, position = 0; i < array.length + 1; i++) {
buffers[i] = new StringBuffer(array[i]);
// str += String.valueOf(buffers[i]);
newArray2[position] = buffers[i];
position++;
// System.out.print(i + "->");
}
return buffers[i];
}
I'm trying to store girl and boy names into an array.
I got most of the code except the storing the files into an array.
This is what girls.txt looks like
Emma 125125
Elaina 415545
Kim 545454
Boys.txt:
Devan 45645
Tom 4545
Chris 4879797
i need help storing the names and numbers from files into array boynames array and girlnames array. I show where i need help with comments in code
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Project1Names {
public static void main(String[] args) {
Scanner inputStream = null;
String[][] boynames = new String[1000][2];
String[][] girlnames = new String[1000][2];
String line = null;
boolean isFoundB = false;
boolean isFoundG = false;
try {
inputStream = new Scanner(new FileInputStream("boys.txt"));
} catch (FileNotFoundException e) {
System.out.println("Problem opening file boys.txt");
System.exit(0);
}
Scanner inputStreamGirls = null;
try {
inputStreamGirls = new Scanner(new FileInputStream("girls.txt"));
} catch (FileNotFoundException e) {
System.out.println("Problem opening file girls.txt");
System.exit(0);
}
int count = 0;
while (count < 1000){
inputStream = boynames[count][0]; //Error here
inputStream = boynames[count][1]; //here
count++;
}
count = 0;
while (count < 1000 ){
inputStreamGirls = girlnames[count][0]; //here
inputStreamGirls = girlnames[count][1]; //here
count++;
}
Scanner keyboard = new Scanner(System.in);
System.out.println("Enter the first name that you would like to find the popularity of.\n Be sure to capitalize the first letter of the name.\n");
String answer = keyboard.next();
count = 0;
while(count < 1000){
if (boynames[count][0] == answer){
System.out.println(boynames[count][0] + " is ranked " + count + " among boys with " + boynames[count][1] + " namings");
isFoundB = true;
}
if (girlnames[count][0] == answer){
System.out.println(girlnames[count][0] + " is ranked " + count + " among girls with " + girlnames[count][1] + " namings");
isFoundG = true;
}
count++;
}
if(isFoundB == false){
System.out.println(answer + " is not ranked among the top 1000 boy names.");
}
if(isFoundG == false){
System.out.println(answer + " is not ranked among the top 1000 girl names.");
}
inputStreamGirls.close();
inputStream.close();
keyboard.close();
}
}
You will need to call the scanner methods to actually read from the input file.
scanner.next() reads one string token from the input.
So instead of this part:
inputStream = boynames[count][0]; //Error here
inputStream = boynames[count][1]; //here
You would do:
boynames[count][0] = inputStream.next();
boynames[count][1] = inputStream.next();
I want to store image into my datatable and while adding colum I want to set its default value, sending you code doing with checkboxes..
public void addCheckBoxesRuntime(){
for (int i = 0; i < InformationOne.Length; i++)
{
dt = new DataColumn(InformationOne[i][1] + " (" + InformationOne[i][0] + " )");
dt.DataType = typeof(Boolean);
viewDataTable.Columns.Add(dt);
dt.DefaultValue = false;
}
}
Make a DataColumn with type string and then store the string binary of the image into the field. Alternatively, use the binary itself with a byte[].
Should work 100%.
Something along the lines of this:
public string ImageConversion(System.Drawing.Image image)
{
if (image == null)
return string.Empty;
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
{
image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Gif);
string value = string.Empty;
for (int intCnt = 0; intCnt <= memoryStream.ToArray.Length - 1; intCnt++)
{
value = value + memoryStream.ToArray(intCnt) + ",";
}
return value;
}
}