How to numerically order array of delimited strings in C# - c#

I'm in a little bit of a bind. I'm working with a legacy system that contains a bunch of delimited strings which I need to parse. Unfortunately, the strings need to be ordered based on the first part of the string. The array looks something like
array[0] = "10|JohnSmith|82";
array[1] = "1|MaryJane|62";
array[2] = "3|TomJones|77";
So I'd like the array to order to look like
array[0] = "1|MaryJane|62";
array[1] = "3|TomJones|77";
array[2] = "10|JohnSmith|82";
I thought about doing a 2 dimensional array to grab the first part and leave the string in the second part, but can I mix types in a two dimensional array like that?
I'm not sure how to handle this situation, can anyone help? Thanks!

Call Array.Sort, but passing in a custom implementation of IComparer<string>:
// Give it a proper name really :)
public class IndexComparer : IComparer<string>
{
public int Compare(string first, string second)
{
// I'll leave you to decide what to do if the format is wrong
int firstIndex = GetIndex(first);
int secondIndex = GetIndex(second);
return firstIndex.CompareTo(secondIndex);
}
private static int GetIndex(string text)
{
int pipeIndex = text.IndexOf('|');
return int.Parse(text.Substring(0, pipeIndex));
}
}
Alternatively, convert from a string array into an array of custom types by splitting the string up appropriately. This will make life easier if you're going to do further work on the array, but if you only need to sort the values, then you might as well use the code above.
You did say that you need to parse the strings - so is there any particular reason why you'd want to parse them before sorting them?

new[] {
"10|JohnSmith|82",
"1|MaryJane|62",
"3|TomJones|77",
}.OrderBy(x => int.Parse(x.Split('|')[0]));

Use an ArrayList (http://msdn.microsoft.com/en-us/library/system.collections.arraylist_methods(VS.80).aspx) so you can sort it.

If the array is large, you will want to extract the initial integers all in one pass, so you are not parsing strings at every comparison. IMO, you really want to encapsulate the information encoded in the strings into a class first. Then sort the array of those objects.
Something like:
class Person {
int Index { get; }
string Name { get; }
int Age { get; } // just guessing the semantic meaning
}
So then:
Map your encoded string into an ArrayList of Person objects.
Then use ArrayList.Sort(IComparer) where your comparer only looks at the Index.
This will likely perform better than using parse in every comparison.

for lolz
Array.Sort(array, ((x,y) => (int.Parse(x.Split('|')[0]) < int.Parse(y.Split('|')[0])) ? -1 : (int.Parse(x.Split('|')[0]) > int.Parse(y.Split('|')[0])) ? 1 : 0));

Related

How to sort a two dimensional array by smallest number?

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.

C# getting array with a string name?

So here's a hypothetical. From someone fairly new to the whole C# and Unity thing:
Suppose for a moment that I have a series of string[] arrays. All of which have similar naming convention. For example:
public string[] UndeadEntities =
{
// stuff
};
public string[] DemonEntities =
{
// stuff
};
Now suppose I want to call one of them at random, I have another list that contains the names of all of those arrays and I return it at random.
My problem is that I grab the name from the array and it's a string, not something I can use. So my question is this:
is there any way for me to use this string and use it to call the above mentioned arrays.
Something like this is what I'm up to but unsure where to go from here and I really would like to avoid making a massive series of If Else statements just for that.
public string[] EnemiesType = { // list of all the other arrays }
public string enemiesTypeGeneratedArrayName = "";
public void GenerateEncounterGroup()
{
enemiesTypeGeneratedArrayName = EnemiesType[Random.Range(0, 12)];
}
Can I nest arrays inside of other arrays? Is there another alternative?
I'm not sure if it is possible at all but if it is, I'll take any pointers as to where to go from there. Thanks.
There are several solutions to your specific problem, an easy one is using Dictionaries:
A Dictionary is a data structure wher you have a key (usually a string) and a value (whatever type you may want to store).
What you can do is at start, initialized a Dictionary were each key is your enemy type, and the value it store is your array, something like:
Dictionary<string, string[]> enemyArrays= new Dictionary<string, string[]>();
.
void Start()
{
enemyArrays["typeA"] = myArrayA;
enemyArrays["typeB"] = myArrayB;
}
Then when you need to get that array, just:
enemiesTypeGeneratedArrayName = EnemiesType[Random.Range(0, 12)];
string[] myRandomArray =enemyArrays[enemiesTypeGeneratedArrayName];
string randomEnemy = myRandomArray[index];
Here you can read more about Dictionary class if you want.
There are other ways to do it, but I think this one is pretty easy to implement in the code you already made, and Dicionaries are cool haha.
I hope is clear:)

Get UTF8.GetBytes from very large stringbuilder

I have a StringBuilder of length 1,539,121,968. When calling StringBuilder .ToString() on it fails with OutOfMemoryException. I tried creating a char array but was not allowed to create such big array.
I need to store it a byte array in UTF8 format. Is it possible?
I'd suggest looking at the documentation for streams. As this might help.
Another way to approach it would be to split it up. As for your last comment stating that you wish to store it as a ByteArray with UTF8 you'd need a char[] as else you'd lose your encoding. I'd reccomend splitting it into many smaller strings (or char[]s) stored in separate objects that can easily be reconstructed. Something like this might suffice, create many StringSlices:
public class StringSlice()
{
public Str {get;}
public Index {get;}
public StringSlice(string str, int index)
{
this.Str = str;
this.Index = index;
}
public static List<string> ReconstructString(IEnumerable<StringSlice> parts)
{
//Sort input by index return list with new strings in order. Probably have to use a buffer on the disc so as not to breach 2GB obj limit.
}
}
In essence what you would be doing here is similar to the way internet packets are split and reconstructed. I'm not entirely sure if I've answered your question but hopefully this comes some way to helping.

Generic way to send an array collection containing only a part of a more complex structure

Let's say a program like this:
class MyClass
{
public int Numbers;
public char Letters;
}
class Program
{
static void Main()
{
var mc = new MyClass[5];
for (var i = 0; i < 5; i++)
{
mc[i].Numbers = i + 1;
mc[i].Letters = (char) (i + 65);
}
}
}
Now, let's suppose an 'X' method that requires ALL the numbers contained in the object mc, in a separate array, that's sent as a parameter.
My first idea is a for, a new integers array, and copy one by one onto its respective position. But, what if the MyClass gets different, now it has strings and floats, and I wanna pull out the strings, now the for has to be completely redefined in its inside part to create the needed array for another 'X' method.
I know of cases where Linq helps a lot, for example, generics for Sum, Average, Count and another numeric functions, and of course, it's combination with lambda expressions.
I'm wondering if something similar exists to make the above arrays of MyClass (and anothers of course) in a faster-generic way?
If you want to use LINQ, you can do something like the following:
int [] numbers = mc.Select<MyClass, int>(m => mc.Number).ToArray();
To make it more generic than that, it gets a bit more complicated, and you may need reflection, or dynamic objects. A simple example with reflection would be:
private TValue[] ExtractFields<TClass, TValue>(TClass[] classObjs, string fieldName)
{
FieldInfo fInfo = typeof(TClass).GetField(fieldName, BindingFlags.Public | BindingFlags.Instance);
if (fInfo != null && fInfo.FieldType.Equals(typeof(TValue)))
return classObjs.Select<TClass, TValue>(c => (TValue)fInfo.GetValue(c)).ToArray();
else
throw new NotSupportedException("Unidentified field, or different field type");
}
And then just call it like:
int [] fields = ExtractField<MyClass, int>(mc, "Number");
If you are using C# 4.0, then you may use dynamic
class MyClass
{
public dynamic Numbers;
public char Letters;
}
EDIT: based on comments
I am not sure if this is what you want:
int[] arr = mc.Select(a => a.Numbers).ToArray<int>();
or without casting
int[] arr = mc.Select(a => a.Numbers).ToArray();
Why not just use Dictionary<int, char>, or if the data type is unknown then simply Dictionary<object, object>
If your goal is to generate a new array which is detached from the original array, but contains data copied from it, the most generic thing you could do would be to define a method like:
T my_array[]; // The array which holds the real things
U[] CopyAsConvertedArray<U>(Func<T,U> ConversionMethod);
That would allow one to generate a new array which extracts items from the original using any desired method.

What is the need Indexers in C#

Today I've gone through what indexers are, but I am bit confused. Is there really a need for indexers? What are the advantages of using an indexer..... thanks in advance
I guess the simplest answer is to look at how you'd use (say) List<T> otherwise. Would you rather write:
string foo = list[10];
or
string foo = list.Get(10);
Likewise for dictionaries, would you rather use:
map["foo"] = "bar";
or
map.Put("foo", "bar");
?
Just like properties, there's no real need for them compared with just named methods following a convention... but they make code easier to understand, in my view - and that's one of the most important things a feature can do.
Indexers let you get a reference to an object in a collection without having to traverse the whole collections.
Say you have several thousands of objects, and you need the one before last. Instead of iterating over all of the items in the collection, you simply use the index of the object you want.
Indexers do no have to be integers, so you can use a string, for example, (though you can use any object, so long as the collection supports it) as an indexer - this lets you "name" objects in a collection for later retrieval, also quite useful.
I think zedo got closest to the real reason IMHO that they have added this feature. It's for convenience in the same way that we have properties.
The code is easer to type and easier to read, with a simple abstraction to help you understand.
For instance:
string[] array;
string value = array[0];
List<string> list;
string value = list[0]; //Abstracts the list lookup to a call similar to array.
Dictionary<string, int> map;
int value = map["KeyName"]; //Overloaded with string lookup.
Indexers allow you to reference your class in the same way as an array which is useful when creating a collection class, but giving a class array-like behavior can be useful in other situations as well, such as when dealing with a large file or abstracting a set of finite resources.
yes , they are very use of
you can use indexers to get the indexed object.
Taken from MSDN
Indexers are most frequently implemented in types whose primary purpose is to encapsulate an internal collection or array.
Full Story
for some reason, use indexer can let you create meaningful index to store or map your data. then you can get it from other side by the meaningful index.
using System;
/* Here is a simple program. I think this will help you to understand */
namespace Indexers
{
class Demo
{
int[] a = new int[10];
public int Lengths
{
get
{
return a.Length;
}
}
public int this[int index]
{
get
{
return a[index];
}
set
{
a[index] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Demo d = new Demo(); // Notice here, this is a simple object
//but you can use this like an array
for (int i = 0; i < d.Lengths; i++)
{
d[i] = i;
}
for (int i = 0; i < d.Lengths; i++)
{
Console.WriteLine(d[i]);
}
Console.ReadKey();
}
}
}
/*Output:
0
1
2
3
4
5
6
7
8
9
*/

Categories

Resources