Solved

Inverse sorting of two-dimensional array

Posted on 2005-04-27
653 Views
I know this kind of question has been asked before, but I just cannot figure out how to do it...

Currently I am creating a medical application which should order diseases based on likelihood, so let's imagine this database (which I put in a 2-dim. array):

string[,] TwoDimArray =
{
{"disease_1", "50"},
{"disease_2", "80"},
{"disease_3", "35" }
};

Now I want to sort the array in a way that puts disease_2 on top (because that one has 80% occurrence), then disease_1 and so on.... so it should have an inverse sorting based on the second dimension of the array.  I haven't been able to figure out how to do this, hopefully anyone can help!
0
Question by:pieter78

LVL 11

Expert Comment

you should put your desease info in a struct or class
like this:
class Desease{
public string name;
public int occurence;
}

and have an array of 'Desease's sorted with a custom comparer (use this override of array sort : public static void Sort(Array, Array, IComparer); )
another way is to make the Desease class implement IComparable, htis way you do not need a custom comparer.

yet another way is to put your data in a datatable (this is specialy suitable if your data comes from a database) and sort that table by a column (or more)
this is done by setting the defaultview.sort property of the datatable to a string identifying the datacolumn to sort by
like this (suppose the table has two columns: Name and Occurence )
YourDataTable.DefaultView.Sort = "Occurence"
now this piece of code will print on the screen the sorted data:
foreach( DataRowView drv in YourDataTable.DefaultView )
{
DataRow dr = drv.Row;
Console.Writeline( "{0},{1}", dr["Name"], dr["Occurence"] );
}

hth,
A.
0

LVL 11

Assisted Solution

Hi,

you could create a class to represent the disease and implement the IComparable interface which an array can use to sort
e.g
class Disease : IComparable
{
private string name;
private double likelihood;

public Disease(string name, double likelihood)
{
this.name = name;
this.likelihood = likelihood;
}

public double getLikelihood()
{
return likelihood;
}
//other methods here

//implementation of IComparable
public int CompareTo(object o)
{
if(o == null)
{
//the compared object is less than by default
return 1;
}
Disease compared = (Disease)o;
if(compared.getLikelihood() == likelihood)
{
//if they are equal
return 0;
}
else if(compared.getLikelihood() > likelihood)
{
//the compared object is greater than this
return -1;
}
else
{
//the compared object is less than
return 1;
}
}
}

this will allow you to use a one dimensional array and use the static method of Array

e.g.
Assuming you have an array of type Disease called D simply pass it into Sort -> Array.Sort(D);

Hope this helps (and works!)

BCS
0

LVL 11

Expert Comment

Should have refreshed before posting !!!

LOL
0

Author Comment

Wow... must admit I am fairly new to C#, have some experience in PHP but not in here... Seems like a lot of work to sort just such a simple piece of code. Anyway, if this is how it must be done, I will have a try, but... no easier options? ;-)
0

LVL 11

Expert Comment

if your data comes from a database via an adapter and you already have it in a datatable then the simpliest way is to aply a view to that datatable.

if not... i think the simpliest way is to implement a class, the way Babycorn-Starfish did in his post.

A.
0

LVL 21

Expert Comment

before you applied the view or anything...

if you get your data off the database (and you do since you mentioned it in your first posting), you would have some kind of an sql statement, something like:

"SELECT desease_name, desease_occurence FROM deseases"

in which case you can just try to add "ORDER BY desease_occurence DESC" and it'll be sorted in the order you'd like.

There are ways of sorting your array as well but using classes is definitely is a better approach. Yet, do you really want to keep you final result in the array or it can be an ArrayList for example?

regards

0

Expert Comment

I agree that you should use some sort of database sort, but if you really want to use arrays, you can:

string[,] TwoDimArray =
{
{"disease_1", "50"},
{"disease_2", "80"},
{"disease_3", "35" }
};

//Create one dimensional array of this array
string[] DiseaseArray, ProbArray;
//get the size of half the 2 dimensional array
int ConvertedTwoDimArraySize = TwoDimArray.Length/2;
//initiate the 1 dimensional arrays
DiseaseArray = new string[ConvertedTwoDimArraySize];
ProbArray = new string[ConvertedTwoDimArraySize];
//loop through all the data from the Two Dimensional Array
for (int i = 0;i<ConvertedTwoDimArraySize;i++)
{
//set the disease array to the first element (0 index based)
DiseaseArray[i] = TwoDimArray[i,0];
//set the probability array to the second element (0+1)
ProbArray[i]= TwoDimArray[i,1];
}

/* Array.Sort sorts a pair of one-dimensional Array objects (one contains the keys and the other contains
* the corresponding items) based on the keys in the first Array using the IComparable interface
* implemented by each key.
* Each key in the keys Array has a corresponding item in the items Array.
* When a key is repositioned during the sorting, the corresponding item in the items Array is
* similarly repositioned. Therefore, the items Array is sorted according to the arrangement
* of the corresponding keys in the keys Array.
* see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemarrayclasssorttopic2.asp
*
*/
//sort the array in ascending order (we will invert later)
Array.Sort(ProbArray,DiseaseArray);
//create a new Two Dimensional Array
string [,] NewTwoDimArray;
NewTwoDimArray = new string[ConvertedTwoDimArraySize,2];

//loop through the array
for (int i = 0;i<ConvertedTwoDimArraySize;i++)
{
//populate the last item (which we want first) into the 0,0 position, and so on
//this will give us inverse sort. Since 0 index based, we have to -1
NewTwoDimArray[i,0]=DiseaseArray[ConvertedTwoDimArraySize-1-i];
NewTwoDimArray[i,1]=ProbArray[ConvertedTwoDimArraySize-1-i];
}

//Do something with the data
for (int i = 0;i<ConvertedTwoDimArraySize;i++)
{
string message = NewTwoDimArray[i,0] + " has an " + NewTwoDimArray[i,1] + " chance of happening";
Console.WriteLine(message);
}
0

Author Comment

I see things are getting complicated... I am developing this software using Crossfire, a plugin for VS.NET that permits you to develop for PDA. And... it does NOT know Array.Sort(), neither the Sort() method for an individual array. I think the first thing I am going to do is contact Appforge, the producer of the software. But any ideas remain welcome....

Yurich: I haven't been experimenting with PDA databases yet, I just called my collection of data a database, but I entered them directly in an array. This is just a demo application, and I have been working with arrays in PHP with great pleasure. And indeed, the ORDER BY ... desc is very helpful in that case.

Just don't know what direction to look in now... I thought arrays would be simple, and in fact: they work. Just the sorting....
0

Author Comment

Well, I wrote Appforge, and this is what they say: "Crossfire does not provide any automatic method for sorting arrays.  If you need to sort an array, you will need to write code to perform the sort operation."  --  Thanks, Appforge... *NOT* !!

So, I must find something else, but for now I just want to stick to the array (I am not that familiar with C# that I can work with datatables and so on, that is something for later ~ besides, it is all for PDA)

I can imagine something else, which is slower and not that elegant, but it is sufficient for this application.
I am writing the Disease and the Chance to an array, and I guess you could just check whether the Chance is smaller than the chance in the line above. If so, insert the data, if not: check if it would be if you insert it one line above, and so on...

But how should I see this in code? Something like:

for (int i=0; i<ArrayLength; i++)
{
if Chance[i] < Chance[i-1]
{// insert data}
else
{// decrease i with 1 and check again}

// then continue with next array element
}

Please help, so far C# has been really demotivating... hope time will improve things. I ordered the book from Murach, hoping that a clear explanation will help...

0

Author Comment

Okay... I have been trying some code and more... reading about it... but still there is a problem. I am working in the .NET Compact Framework (I left Crossfire for a while, then at least there is 1 standard). In the current version of the Compact Framework (1.1) there is no support for the SortedList, which would be a good suggestion. So, I went back to the IComparer, which I earlier used fo a working test app. But now I cannot get it to work....

Hope one of you guys can help me. I used a struct, and from there a normal array (so no multidim. arrays anymore... indeed too complicated). Who knows how to solve this?
(Question was: inverse sorting of Diseases by Chance)

----------------------------------------------------------------------------------------------------------------------------------
public class ChanceReverserClass : IComparer
{
// Calls CaseInsensitiveComparer.Compare with the parameters reversed.
int IComparer.Compare( Object x, Object y )
{
return( (new CaseInsensitiveComparer()).Compare( y, x ) );
}
}

public struct DiseaseChance
{
public DiseaseChance(string disease, int chance)
{
Disease = disease;
Chance  = chance;
}
public string Disease;
public int    Chance;
}

public DiseaseChance[] DiseaseArray = new DiseaseChance[]
{
new DiseaseChance("One", 5),
new DiseaseChance("Two", 2),
new DiseaseChance("Three", 7)
};

private void Form1_Load(object sender, System.EventArgs e)
{
IComparer ChanceComparer = new ChanceReverserClass();
Array.Sort(DiseaseArray, 0, DiseaseArray.Length, ChanceComparer);
// further attempts fail...
}
----------------------------------------------------------------------------------------------------------------------------------
0

LVL 11

Accepted Solution

Hi again,

I simply 'bolted on' the IComparable Interface to your struct, this allows it to be used by the object implementing the IComparer interface.

Not sure how purists would view this, it seemed wierd using an Interface on a struct, especially one whose sole argument is of type object which is subsequently cast
to a struct. Wierd as i've not done this before, must read more .NET documentation - used to classes.

Hope this helps, just copy and paste the altered struct - it seems to work, let me know if there are futher problems.

Incidentally, just out as an aside, why a struct - not a criticism just purely, well nosy if i'm honest!

using System;
using System.Collections;

namespace ConsoleApplication3
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{

static void Main(string[] args)
{
DiseaseChance[] DiseaseArray = new DiseaseChance[]{new DiseaseChance("One", 5),      new DiseaseChance("Two", 2),new DiseaseChance("Three",7)};
IComparer ChanceComparer = new ChanceReverserClass();
try
{
Array.Sort(DiseaseArray, 0, DiseaseArray.Length, ChanceComparer);
}
catch(Exception e)
{
Console.WriteLine(e.ToString() + "\n" + e.StackTrace);
}
}

}
}
public class ChanceReverserClass : IComparer
{
// Calls CaseInsensitiveComparer.Compare with the parameters reversed.
int IComparer.Compare( Object x, Object y )
{
return( (new CaseInsensitiveComparer()).Compare( y, x ) );
}
}

public struct DiseaseChance : IComparable
{
public DiseaseChance(string disease, int chance)
{
Disease = disease;
Chance  = chance;
}
public string Disease;
public int    Chance;
//implementation of IComparable
public int CompareTo(object o)
{
if(o == null)
{
//the compared object is less than by default
return 1;
}
DiseaseChance compared = (DiseaseChance)o;
if(compared.Chance == this.Chance)
{
//if they are equal
return 0;
}
else if(compared.Chance > this.Chance)
{
//the compared object is greater than this
return -1;
}
else
{
//the compared object is less than
return 1;
}
}

}

Cheers

Jay
0

Author Comment

Well, about the difference between classes and structs: I don't know yet ;-)   I followed the advice of somebody else who told me about this, and because (in general) I could understand it, I tried. Basically, it is the same like your code....  I ordered a good book about C#, for this moment I must admit my knowledge seems to be very limited (which is true, as a matter of fact).  If you say classes are better, I can change....

So one stupid question maybe, but for now I can't figure out anymore.... how do I write the results to a screen?
I couid make an array e.g. called DiseaseOrderedList and add items to it... but will that be as simple as DiseaseOrderedList.Add(o.ToString()) ?
(would be nice to combine chance with this, but not necessarily for now)
0

LVL 11

Expert Comment

Hi,

I think if you add some kind of method e.g.

//one to output to terminal
public void PrintInfo()
{
Console.WriteLine("Disease name: " + Disease + " Disease Probability: " + Chance");
}
//one to produce a string to use in a dialog box or something
public string ToString()
{
return ("Disease name: " + Disease + " Disease Probability: " + chance");
}

to illustrate this add the following to the method main after the sorting bit:
foreach(DiseaseChance d in DiseaseArray)
{
d.PrintInfo();
}

>>If you say classes are better, I can change....
I'm not too sure either, that's why i asked :).
I've a book on VB.NET which explains the differences between Struct(ure)s and Classes but i've yet to do anything which makes the differences obvious; Structs are Value types, Classes(Objects thereof) are reference types.

Jay

0

LVL 11

Expert Comment

0

Author Comment

Well, I guess BCS answerd my question... at least now it works using code someone here helped me with, but he suggested exactly the same manner (independently). So in my opinion, the question I asked has been answered, so let's close this topic. If I run into problems with the implementation I will open a new one, seems fair enough...

Thanks !!
0

Featured Post

Anonymous Types in C# by Ivo Stoykov Anonymous Types are useful when  we do not need to follow usual work-flow -- creating object of some type, assign some read-only values and then doing something with them. Instead we can encapsulate this read…
This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
Need more eyes on your posted question? Go ahead and follow the quick steps in this video to learn how to Request Attention to your question. *Log into your Experts Exchange account *Find the question you want to Request Attention for *Go to the e…
In this sixth video of the Xpdf series, we discuss and demonstrate the PDFtoPNG utility, which converts a multi-page PDF file to separate color, grayscale, or monochrome PNG files, creating one PNG file for each page in the PDF. It does this via a c…