When creating webservices, in c#, I have found it very useful to pass back jagged arrays, i.e. string[][]
I also found a neat trick to build these in a simple way in my code, which was to create a List and convert it by doing a ToArray() call.
e.g.
public string[][] myws() {
List<string[]> output = new List<string[]>();
return output.ToArray();
}
I would like to be able to employ a similar solution, but I can't think how to do something similar with a 3 level jagged array or string[][][], without resorting to loops and such.
Regards
Martin
You can get there by doing a Select() which converts each inner List<string> to an array using ToArray(), and then converting those results using ToArray():
var x = new List<List<string[]>>();
string[][][] y = x.Select(a => a.ToArray()).ToArray();
And so on for as many levels deep as you'd want to go.
Related
I'm making a program that counts how many lines of code are in a folder where you input the extension you want to check for (like .cs) and it lists all of the files with that extension and their lines of code like this:
1. BackgroundProcesses.cs: 153
2. App.xaml.cs: 15
3. MainTableManifest.cs: 41
At the moment, I'm just using Directory.GetFiles() to get the files and they're not in any particular order. However, I want to sort each file by how many lines it has to display it from smallest to largest for easy viewing of what the largest files are with an output like this:
1. App.xaml.cs: 15
2. MainTableManifest.cs: 41
3. BackgroundProcesses.cs: 153
Here's what my two-dimensional jagged array basically looks like:
string[][] arr = new string[][] {
new string[]{"file1", "324"},
new string[]{"file2", "1903"},
new string[]{"file3", "617"}
};
Obviously, I would need to convert the strings to numbers when sorting (I don't think you can have a jagged array with different array types). Any ideas on how to do this to convert that jagged array to something like this?
string[][] arr = new string[][] {
new string[]{"file1", "324"},
new string[]{"file2", "617"},
new string[]{"file3", "1903"}
};
You should use ValueTuple instead of Jagged Arrays.
(string Filename, int Lines)[] files = ...
After that you can use Linq for sorting
var sorted = files
.OrderBy(item => item.Lines)
.ThenBy(item => item.Filename);
One of the major points of an object oriented programming language such as C# is to allow you to define custom objects and have behaviours related to them rather than complex structures of native types.
Have you tried creating a custom object to represent this data that can then be sorted accordingly?
e.g.
public class FileRecord
{
public string FileName { get; }
public int NumberOfLines { get; }
public FileRecord(string fileName, int numberOfLines)
{
this.FileName = fileName;
this.NumberOfLines = numberOfLines;
}
}
Then you can either make this class implement IComparable or define a custom comparer for the sort. My preference would be for using a custom comparer because you may want to sort using different criteria and the same class elsewhere.
This would look like:
public class FileRecordComparer : IComparer<FileRecord>
{
public int Compare(FileRecord x, FileRecord y)
{
// Could handle nulls here if you're expecting nulls
int lineCompare = x.NumberOfLines.CompareTo(y.NumberOfLines);
if (lineCompare == 0)
return x.FileName.CompareTo(y.FileName);
else
return lineCompare;
}
}
Then you can have the following code to sort your array (you'll have to populate it in the way you are currently of course)
// Could use a list here if you don't know the number of files
FileRecord[] records = new FileRecord[numberOfFiles];
// ...
// Populate the records as you do currently, but creating instances of FileRecord
// ...
Array.Sort(records, new FileRecordComparer());
Try
var files = arr.OrderBy(x =>Convert.ToInt64(x[1]));
you could use Tuple with Linq to simplify your problem get the files and number of lines in same time:
(string Filename, int numberLines)[] files = Directory.GetFiles(#"d:\", "*.cs")
.Select(f => (f, File.ReadLines(f).Count()))
.OrderBy(f => f.Item2).ToArray();
foreach (var file in files)
{
Console.WriteLine($"file:{file.Filename} lines:{file.numberLines}");
}
if you have lot of files in your directory, i suggest you to use EnumerateFiles instead of GetFiles.
Coming from Python, I could easily do array[0][0], but doesn't seem like it in C#.
When I try to fetch data from my MySQL database, it gives me a 2D array, hence the need to use a 2D array.
Array looks like this:
[[hello], [world]]
I'd like to just fetch the string "hello". How would I manage that?
You use
string value = array[0,0];
Here:
var array= new String[,] {{"Hello","World"}};
string value=array[0,0];
You can access multidimensional arrays like this:
int val = a[2,3];
The above statement takes 4th element from the 3rd row of the array.
In your case it would be:
string val = a[0,0];
Pretty straightforward: arrray[0, 0]
Reference
I am getting the following error message with the code below. I thought the data type List<double> was the same as double[] but that C# required it to be instantiated using the first syntax for the variable to work as an object. What am I doing wrong or is my thinking wrong?
Cannot implicitily convert type `double[]` to `System.Collections.Generic.List<double>`
Code:
private void RunScript(List<Curve> crv, double nb, ref object DivPts)
{
List<double> nbtemp = new List<double>();
List<double> Divpt = new List<double>();
for(int i = 0; i < crv.Count;i = i + 2)
{
nbtemp = crv[i].DivideByLength(nb, true);
}
Divpt = nbtemp;
No, a list is not an array, even though the concepts are somewhat similar. The List<T> class in C# is actually implemented with a behind-the-scenes array.
If you want to set a List from an array, you can use something like this:
nbtemp = new List<double>(crv[i].DivideByLength(nb, true));
that will create a new List, and initialize it with the array. You can also use the AddRange method of the List, if you would like to append an array to an existing list, like this:
nbtemp.AddRange(crv[i].DivideByLength(nb, true));
You can't convert from Array to List, but you can easily call:
nbtemp = crv[i].DivideByLength(nb, true).ToList();
Or, since you already have to Lists defined, you could also:
nbtemp.AddRange(crv[i].DivideByLength(nb, true));
You are using an assignment and it is hard to tell what DivideByLength returns, if a single value then use:
nbtemp.Add(crv[i].DivideByLength(nb, true));
Otherwise, if it is returning an array, try changing your definition to allow the list to contain arrays:
List<double[]> nbtemp = new List<double[]>();
Note that List is not equivalent to double[]. List has many features that a simple array does not. You can see the differences by looking at the two different MSDN articles for which methods are publicly exposed.
List
Array
Also, your for loop as it stands is using an assignment. Without a change to that part of the code, you will only assign the last iteration of the for loop to the variable nbtemp (assuming you remove the error)
They are both IEnumerable implementers but they are not equivalent types. You will need to perform a cast or a method call. In the code above I would say you'd need:
nbtemp = (crv[i].DivideByLength(nb, true)).ToList();
or
nbtemp.AddRange(crv[i].DivideByLength(nb, true));
What is the best way to convert a List of primitive longs to an array of strings?
I think I'm looking for something fancier than writing my own loop, etc..
This should do the trick:
string[] arr = list.Select(l => l.ToString()).ToArray();
This is worth checking against the performance of a select statement.
string[] result = Array.ConvertAll(list.ToArray(), i => i.ToString());
I have 2 separate List and I need to compare the two and get everything but the intersection of the two lists. How can I do this (C#)?
If you mean the set of everything but the intersection (symmetric difference) you can try:
var set = new HashSet<Type>(list1);
set.SymmetricExceptWith(list2);
You can use Except to get everything but the intersection of the two lists.
var differences = listA.Except(listB).Union(listB.Except(listA));
If you want to get everything but the union:
var allButUnion = new List<MyClass>();
(The union is everything in both lists - everything but the union is the empty set...)
Do you mean everything that's only in one list or the other? How about:
var allButIntersection = a.Union(b).Except(a.Intersect(b));
That's likely to be somewhat inefficient, but it fairly simply indicates what you mean (assuming I've interpreted you correctly, of course).
Here is a generic Extension method. Rosetta Code uses Concat, and Djeefther Souza says it's more efficient.
public static class LINQSetExtensions
{
// Made aware of the name for this from Swift
// https://stackoverflow.com/questions/1683147/get-the-symmetric-difference-from-generic-lists
// Generic implementation adapted from https://www.rosettacode.org/wiki/Symmetric_difference
public static IEnumerable<T> SymmetricDifference<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
// I've used Union in the past, but I suppose Concat works.
// No idea if they perform differently.
return first.Except(second).Concat(second.Except(first));
}
}
I haven't actually benchmarked it. I think it would depend on how Union vs. Concat are implemented. In my dreamworld, .NET uses a different algorithm depending on data type or set size, though for IEnumerable it can't determine set size in advance.
Also, you can pretty much ignore my answer - Jon Skeet says that the HashSet method "Excellent - that looks like the best way of doing it to me."
Something like this?
String[] one = new String[] { "Merry", "Metal", "Median", "Medium", "Malfunction", "Mean", "Measure", "Melt", "Merit", "Metaphysical", "Mental", "Menial", "Mend", "Find" };
String[] two = new String[] { "Merry", "Metal", "Find", "Puncture", "Revise", "Clamp", "Menial" };
List<String> tmp = one.Except(two).ToList();
tmp.AddRange(two.Except(one));
String[] result = tmp.ToArray();
var theUnion = list1.Concat(list2);
var theIntersection = list1.Intersect(list2);
var theSymmetricDifference = theUnion.Except(theIntersection);
Use Except:
List<int> l1 = new List<int>(new[] { 1, 2, 3, 4 });
List<int> l2 = new List<int>(new[] { 2, 4 });
var l3 = l1.Except(l2);