c# concatenate List<string> plus string - c#

I have this List in c#:
List<string> cad_analise = new List<string>();
And I added this:
cad_analise.Add("FQ");
cad_analise.Add("CR");
So, I would like to do this
var joinstring = "";
joinstring = cad_analise[0] + ", second is " + cad_analise[1] + ", join the words.";
But, I am getting the following error:
Index was out of range. Must be non-negative and less than the size of the collection.
I did some tests here and I fought that the error is when I join the cad_analise[0] and cad_analise[1].
See here the error: https://dotnetfiddle.net/3rowFv
Here is working perfectly: https://dotnetfiddle.net/G6JwFs

In your code example https://dotnetfiddle.net/3rowFv you'll have these bools:
bool has_analiseCR = true;
bool has_analiseFQ = true;
bool has_analisePCB = false;
bool has_analise2FAL = false;
bool has_analiseGP = false;
Then you are checking if it's true add a value to has_analise List<string> if false add it to cad_analise List<string>. So in the end:
has_analise will look like:
[0] => "CR"
[1] => "FQ"
then you are trying on line 74:
print_analise_cad = "Análise " + has_analise[0] + ", " + has_analise[1] + " e " + has_analise[2] + " do equipamento " + NumSerie_app + " e amostra de " + data_amostra + " foram cadastradas.";
Where you are calling has_analise[2] this index does not exits as shown above.
The list only has a value on index [0] and [1] and not on [2]
Also you are checking on number_analise_cad if (number_analise_cad == 3) and not on the length of number_analise_existente whits is based on the lenght of has_analise List<string>
This is the reason why you are getting the index out of range exception.

As you can verify here, your (as posted in the question) code works.
The only issue I found is a missing semicolon at the end of the last line (but I guess this was a copy/paste error):
joinstring = cad_analise[0] + ", second is " + cad_analise[1] + ", join the words.";

Related

How do i working with Arrays in a While loop?

I have tried to wipe this data while trying to export a database into my program.
The basic problem is that I do not know why he can not use LIKE in my SQL statement.
So I wanted to catch all DataRows and write them into an array, which I can edit later.
The program throws an exception:
Error message: System.IndexOutOfRangeException: "The index was outside the array area."
If I did something unusual or wrong in my Post I sincerely apologies, this is my first entry in this forum.
Code:
public void TestQuery()
{
string file = #"C:\Users\Michael\Downloads\7z1900-x64.msi";
// Get the type of the Windows Installer object
Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
// Create the Windows Installer object
WindowsInstaller.Installer installer = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);
// Open the MSI database in the input file
Database database = installer.OpenDatabase(file, 0);
// Open a view on the Property table for the version property
View view = database.OpenView("SELECT * FROM `File`");
// Execute the view query
view.Execute(null);
// Get the record from the view
Record record = view.Fetch();
int i = 1;
string[] sreturns = new string[60];
while (record != null)
{
Console.WriteLine("Ausgabe: " + record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
record = view.Fetch();
sreturns[i] = record.get_StringData(0).ToString();
i++;
}
}
First thing I see is that you're starting at 1, while (C#) arrays are 0-based.
In you screenshot I see that i is 60, so that would be the problem. Index 60 doesn't actually exist in your array, as it goes from 0 to 59.
You can add i < sreturns.Length to make sure you are in the array range.
Also, make sure you start with i = 0 and not 1.
int i = 0;
string[] sreturns = new string[60];
while (record != null && i < sreturns.Length)
{
Console.WriteLine("Ausgabe: " + record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
record = view.Fetch();
sreturns[i] = record.get_StringData(0).ToString();
i++;
}
Why not using a list instead of an array?
List<string> sreturns = new List<string>();
while (record != null)
{
try
{
Console.WriteLine("Ausgabe: " + record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
record = view.Fetch();
var result = record.get_StringData(0);
sreturns.Add(result.ToString());
}
catch (Exception e)
{
Console.WriteLine("No record...");
}
}
This way you dont need to worry about the array size - its maintainable -efficient - and if in the future the size change you don't have to worry about it.
List documentation here
What is the query with LIKE that you have tried? The following should work:
SELECT * FROM File WHERE FileName LIKE '%.exe' OR FileName LIKE '%.msi'
EDIT: On further investigation (https://learn.microsoft.com/en-us/windows/win32/msi/sql-syntax), the documentation seems to imply that the LIKE operator is not supported. But you could start off with an IS NOT NULL and do more complex filtering in the loop, like you're doing.
EDIT 2, expanding on Alex Leo's answer.
List<string> sreturns = new List<string>();
while (record != null)
{
Console.WriteLine("Ausgabe: " + record.get_StringData(0) + '=' + record.get_StringData(1) + '=' + record.get_StringData(2) + '=' + record.get_StringData(3));
var result = record.get_StringData(0);
if(!string.IsNullOrWhiteSpace(result) && (result.EndsWith(".exe") || result.EndsWith(".msi")))
{
sreturns.Add(result.ToString());
}
record = view.Fetch();
}
Note that the view.Fetch() inside the while loop has been moved to the end, or you would skip the first record, as well as get another null reference when the last record has already been read, but the while loop executes one more time.

How to set prefix in string in join?

I have this strings:
string[] codes = new string[]{"66000110", "66000001", "66000121"};
I want to make join on strings above:
string filter = string.Join(" OR " + some_ID + "=", codes );
The resukt I get is:
some_ID=66000110 OR some_ID=66000001 OR some_ID=66000121
While I need the string like that(OR missing on start string):
OR some_ID=66000110 OR some_ID=66000001 OR some_ID=66000121
How do I fix elegantic way to get OR on start of the string?
It seems that you are building some kind of SQL; if it's your case, try switching to IN:
string filter = $" OR {some_ID} IN ({string.Join(", ", codes)})";
And you'll get a more readable equivalent
" OR some_ID IN (66000110, 66000001, 66000121)"
You can use a combination of LINQ and Concat():
string filter = string.Concat(codes.Select(c => " OR " + some_ID + "=" + c));
Why not something like this?
string filter = " or " + string.Join(" OR " + some_ID + "=", codes );

C# How to check a Listbox for a string + object?

I'm trying to search for a certain number(object) in a listbox which comes together with a string in order to highlight it. In the following bit of code i override a ToString() method to contain all my objects.
public override string ToString()
{
string reservatiestring;
reservatiestring = "Kamer: " + roomNumber + "" + " Op datum: " + datum + " Aantal personen: " + personen.Count + " Naam: " + reservatienaam;
return reservatiestring;
}
Following this I add it to my listbox in the following bit of code:
listBox1.Items.Add(reservatie.ToString());
I now want to search for all the items in my listbox containing the same roomNumber object. To do this i tried the Contains() method with the text before it: "Kamer: " and the object which I'm looking for +comboBox1.SelectedItem. This however always fails and my code goes to the else option giving me the error message.
private void buttonSearch_Click(object sender, EventArgs e)
{
listBox1.SelectionMode = SelectionMode.MultiExtended;
Reservations reservaties = new Reservations();
reservaties.roomnumberstring = "Kamer: " + comboBox1.SelectedValue;
for (int i = listBox1.Items.Count - 1; i >= 0; i--)
{
if (listBox1.Items[i].ToString().ToLower().Contains(("Kamer: " + comboBox1.SelectedValue)))
{
listBox1.SetSelected(i, true);
}
else
{
MessageBox.Show("error");
}
Please note: All my roomNumber objects are stored in the combobox, so whenever i select for example roomNumber 3 in my combobox and hit search all the items in the listbox containing "Kamer: 3" should be selected.
The roomnumberstring is a option I tried which did not work unfortunately.
reservaties.roomnumberstring = "Kamer: " + comboBox1.SelectedValue;
Your override of the ToString method is wrong and won't modify anything. Try this :
public override string ToString(this string reservatiestring)
{
reservatiestring = "Kamer: " + roomNumber + "" + " Op datum: " + datum + " Aantal personen: " + personen.Count + " Naam: " + reservatienaam;
return reservatiestring;
}
I can see one thing that might make your code fail. you are comparing
.ToLower()
with "Kamer", where the "K" isn´t in lowercase

Create a dropdownlist of checkboxes using EPPlus

I am using EPPlus (http://epplus.codeplex.com/) to create Excel files in my ASP.NET application. I was wondering if anyone knows if it's possible to create a dropdownlist with checkboxes in one cell. I've checked the documentation, but found nothing so far. I've also tried Googling it but haven't found anything in the right direction yet.
This question on their forum is actually a pretty good demonstration of what I'm looking for, but it hasn't received any answers: http://epplus.codeplex.com/discussions/585879
Does anyone happen to have any ideas and can point me in the right direction?
You can use:
var validationCell = sheet.DataValidations.AddListValidation("A1");
validationCell.Formula.Values.Add("a");
validationCell.Formula.Values.Add("b");
validationCell.Formula.Values.Add("c");
...
but you can choose only one single value. I think that multiple values are not supported by excel.
For others reference, here is how I could enable multiple values select:
By inserting VBA Code:
see how to do it in here , using EPPlus you can insert VBA code using something like:
package.Workbook.CreateVBAProject();
worksheet.CodeModule.Code = code;
This following code did the trick:
using (var package = new ExcelPackage(new System.IO.FileInfo("D:\\b.xlsm")))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("11");
var validationCell = worksheet.DataValidations.AddListValidation("A1");
validationCell.Formula.Values.Add("a");
validationCell.Formula.Values.Add("b");
validationCell.Formula.Values.Add("c");
string code = "Private Sub Worksheet_Change(ByVal Target As Range)\n" +
"Dim Oldvalue As String\n" +
"Dim Newvalue As String\n" +
"Application.EnableEvents = True\n" +
"On Error GoTo Exitsub\n" +
"If Target.Address = \"$A$1\" Then\n" +
" If Target.SpecialCells(xlCellTypeAllValidation) Is Nothing Then\n" +
" GoTo Exitsub\n" +
"Else: If Target.Value = \"\" Then GoTo Exitsub Else\n" +
" Application.EnableEvents = False\n" +
"Newvalue = Target.Value\n" +
"Application.Undo\n" +
"Oldvalue = Target.Value\n" +
" If Oldvalue = \"\" Then\n" +
" Target.Value = Newvalue\n" +
"Else\n" +
" If InStr(1, Oldvalue, Newvalue) = 0 Then\n" +
" Target.Value = Oldvalue & \", \" & Newvalue\n" +
"Else: \n" +
" Target.Value = Oldvalue\n" +
"End If\n" +
"End If\n" +
"End If\n" +
"End If\n" +
"Application.EnableEvents = True\n" +
"Exitsub: \n" +
" Application.EnableEvents = True\n" +
"End Sub";
package.Workbook.CreateVBAProject();
worksheet.CodeModule.Code = code;
package.Save();
}

How do you display items from a list in a message box?

I am working on a project that needs to display a list of people that have above average income. The source data is a List<IncomeData> (id is the unique id for the person):
public struct IncomeData
{
public string id;
public double household;
public income;
}
public double belowAverage = 0, total, belowAveragePercent;
IncomeData surveyStruct;
List<IncomeData> surveyList = new List<IncomeData>();
List<string> aboveAverage = new List<string>();
Here is how I determine if a person has above average income. If a person has above average income, I add the id and income from the temporary instance of the surveyStruct to the above average list of string values:
//Determine poverty.
if (surveyStruct.income - 3480 * surveyStruct.household <= 6730)
{
belowAverage += 1;
}
else if (surveyStruct.income - 3480 * surveyStruct.household >= 6730)
{
aboveAverage.Add(surveyStruct.id);
aboveAverage.Add(surveyStruct.income.ToString());
}
And here is the code that displays the desired information in a message box. (The aboveAverage list is added in here, too.)
private void reportsToolStripMenuItem_Click(object sender, EventArgs e)
{
//Display reports 1, 2, and 3.
MessageBox.Show("Your Entry:\nID Code: " + surveyStruct.id +
"\nHousehold: " + surveyStruct.household.ToString() +
" people\nIncome: " + surveyStruct.income.ToString("C") +
"\n\nPeople Above Average:\n" + aboveAverage +
"\n\nAnd " + belowAveragePercent + "% of people are below average.");
}
Now, here's the problem: Instead of a seeing a list of values in the message box, I am seeing System.Collections.Generic.List`1[System.String] where the IDs and incomes of the above average people should be. Can somebody please tell me what I am doing wrong and how I can display a list values in a message box?
At the end of your question you ask: How I can display a List<IncomeData> in a message box?
So, the core of your question is converting your list of values to a string so that you can pass that string as an argument to MessageBox.Show().
The LINQ Extension Method Enumerable.Aggregate() offers an ideal solution for this problem. Say your List<IncomeData> looks something like this (I've omitted the household field for brevity):
var incomes = new List<IncomeData>() {
new IncomeData("abc0123", 15500),
new IncomeData("def4567", 12300),
new IncomeData("ghi8901", 17100)
};
The following LINQ query will convert that List<IncomeData> into a string:
string message = incomes.
Select(inc => inc.ToString()).
Aggregate((buffer, next) => buffer + "\n" + next.ToString());
To eliminate the need to call Select(), you can instead use the two-argument version of Enumerable.Aggregate(). This approach also allows you to specify a heading as the seed value for your accumulator:
string message2 = incomes.
Aggregate(
"Income data per person:",
(buffer, next) => buffer + "\n" + next.ToString());
That is equivalent to the following where the argument types have been made explicit:
string message = incomes.
Aggregate<IncomeData, string>(
"Income data per person:",
(string buffer, IncomeData next) => buffer + "\n" + next.ToString());
See the following (and online demo) for a complete working example preceded by its expected output.
Expected Output
Income data per person:
Id: abc0123, Income:15500
Id: def4567, Income:12300
Id: ghi8901, Income:17100
Demonstration Program
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqAggregateDemo
{
public class Program
{
public static void Main(string[] args)
{
var incomes = new List<IncomeData>() {
new IncomeData("abc0123", 15500),
new IncomeData("def4567", 12300),
new IncomeData("ghi8901", 17100)
};
string message = incomes.
Select(inc => inc.ToString()).
Aggregate((buffer, next) => buffer + "\n" + next.ToString());
Console.WriteLine("Income data per person:\n" + message);
}
public struct IncomeData
{
public readonly string Id;
public readonly int Income;
public IncomeData(string id, int income)
{
this.Id = id;
this.Income = income;
}
public override string ToString()
{
return String.Format(
"Id: {0}, Income:{1}",
this.Id,
this.Income);
}
}
}
}
First, make aboveAverage a List<IncomeData>, and add the IncomeDatas that match into that list.
Then, you need to define a ToString for your custom struct, something like this:
public override void string ToString()
{
return string.Format("The id is {0}, the household is {1} and the income is {2}.", id, household, income);
}
Then, in your MessageBox.Show call, you need to replace aboveAverage with
aboveAverage.Aggregate((a,b) => a.ToString() + Enviroment.NewLine + b.ToString())
Should make it show properly.
Sorry about the formatting,I'm on mobile.
StringBuilder is one choice:
StringBuilder aboveAverage = new StringBuilder();
//Determine poverty.
if (surveyStruct.income - 3480 * surveyStruct.household <= 6730)
{
belowAverage += 1;
}
else if (surveyStruct.income - 3480 * surveyStruct.household >= 6730)
{
aboveAverage.Append(string.Format("id: %s, income: %s\n",
surveyStruct.id, surveyStruct.income.ToString());
}
And you will need a ToString() for the string builder, like this:
MessageBox.Show("Your Entry:\nID Code: " + surveyStruct.id + "\nHousehold: " + surveyStruct.household.ToString() + " people\nIncome: " + surveyStruct.income.ToString("C") + "\n\nPeople Above Average:\n" + aboveAverage.ToString() + "\n\nAnd " + belowAveragePercent + "% of people are below average.");
You could do it with join if you leave aboveAverage as a list, like this:
string.Join(aboveAverage,Environment.NewLine);
In your current code -- but that would not look so nice.
You could also do it with Linq, you want to see that?
Ok, here is a sexy one line version: (all questions should have a one line linq answer):
(the using and indent don't count, they are just there to make the code more readable!)
using NL = Environment.NewLine;
    
string indent = "    ";
MessageBox.Show(
"Your Entry:" + NL +
"ID Code: " + surveyStruct.id + NL +
"Household: " + surveyStruct.household.ToString() + " people" + NL +
"Income: " + surveyStruct.income.ToString("C") + NL + NL +
"People Above Average:" + NL +
indent + string.Join(NL+indent,
surveyList.Where(s => (s.income - 3480) * s.household >= 6730)
.Select(s => "ID: "+s.id+" $"+s.income.ToString).ToArray()) + NL +
"And " + (surveyList.Where(s => ((s.income - 3480) * s.household) <= 6730).Count() / surveyList.Count()) * 100 + "% of people are below average.");

Categories

Resources