I have a text file that is being read in and then stored in a string[] which I then then convert into an int[], my bubblesort then should sort it but it doesn't because the values from the text files are decimals. So my question is how do I convert either the string[] or int[] to something that can accept decimal values, such as a double[] if there is such a thing. Thanks.
Code:
string[] sh1OpenData = File.ReadAllLines("SH1_Open.txt");
...
else if(input2.ToLower() == "open") //----
{
int[] intSh1OpenData = new int[sh1OpenData.Length];
for (int x = 0; x < sh1OpenData.Length; x++)
{
intSh1OpenData[x] = Convert.ToInt32(sh1OpenData[x]);
}
Console.WriteLine("\n");
Console.WriteLine("Unsorted");
for (int i = 0; i < intSh1OpenData.Length; i++)
{
Console.Write(intSh1OpenData[i] + " ");
Console.WriteLine(" ");
}
int temp = 0;
for (int write = 0; write < intSh1OpenData.Length; write++)
{
for (int sort = 0; sort < intSh1OpenData.Length - 1; sort++)
{
if (intSh1OpenData[sort] > intSh1OpenData[sort + 1])
{
temp = intSh1OpenData[sort + 1];
intSh1OpenData[sort + 1] = intSh1OpenData[sort];
intSh1OpenData[sort] = temp;
}
}
}
Console.WriteLine("\n\n\nSORTED");
for (int i = 0; i < intSh1OpenData.Length; i++)
Console.Write(intSh1OpenData[i] + "\n");
}
You should not be using int to do comparisons on string. Use String.Compare(return 0 if equal, -1 if less than, or 1 if greater than) or List.Sort() to sort string array
Pretty simple with LINQ
var asDouble = sh1OpenData.Select(x => Double.Parse(x)).OrderBy(x => x).ToArray();
This will give you a sorted (ascending order) array of Double.
Note: this assumes that all of sh1OpenData can be parsed as a Double, and will throw an exception if not.
The only changes that you will need to make are listed below:
double[] intSh1OpenData = new double[sh1OpenData.Length]; // double[] instead of int[]
for (int x = 0; x < sh1OpenData.Length; x++)
{
intSh1OpenData[x] = Convert.ToDouble(sh1OpenData[x]); // Convert to Double
}
also change the declaration of your temp variable to double temp;
Something that you could read through since you mentioned that you are new to programming:
C# Sort Arrays and Lists Examples
MSDN: List.Sort Method
Related
I have a string array defined in c# as
string[,] options = new string[100,3];
Throughout the code it gets populated with data but not always filled.
So if I have 80 parts of it filled and 20 parts of it not filled. The 20 parts have nulls in them or 60 nulls at the end. Is there an easy way to resize the array so that after filling it the array is the same as
String[,] options = new string[80,3];
It would have to be resized based on the position of the first set of 3 nulls it found.
If this was a jagged array I would have done
options = options.Where(x => x != null).ToArray();
The method is quite long, because it has to check every row twice...
public static string[,] RemoveEmptyRows(string[,] strs)
{
int length1 = strs.GetLength(0);
int length2 = strs.GetLength(1);
// First we count the non-emtpy rows
int nonEmpty = 0;
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i, j] != null)
{
nonEmpty++;
break;
}
}
}
// Then we create an array of the right size
string[,] strs2 = new string[nonEmpty, length2];
for (int i1 = 0, i2 = 0; i2 < nonEmpty; i1++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i1, j] != null)
{
// If the i1 row is not empty, we copy it
for (int k = 0; k < length2; k++)
{
strs2[i2, k] = strs[i1, k];
}
i2++;
break;
}
}
}
return strs2;
}
Use it like:
string[,] options = new string[100, 3];
options[1, 0] = "Foo";
options[3, 1] = "Bar";
options[90, 2] = "fiz";
options = RemoveEmptyRows(options);
As suggested by Alexei, there is another way of doing this:
public static string[,] RemoveEmptyRows2(string[,] strs)
{
int length1 = strs.GetLength(0);
int length2 = strs.GetLength(1);
// First we put somewhere a list of the indexes of the non-emtpy rows
var nonEmpty = new List<int>();
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i, j] != null)
{
nonEmpty.Add(i);
break;
}
}
}
// Then we create an array of the right size
string[,] strs2 = new string[nonEmpty.Count, length2];
// And we copy the rows from strs to strs2, using the nonEmpty
// list of indexes
for (int i1 = 0; i1 < nonEmpty.Count; i1++)
{
int i2 = nonEmpty[i1];
for (int j = 0; j < length2; j++)
{
strs2[i1, j] = strs[i2, j];
}
}
return strs2;
}
This one, in the tradeoff memory vs time, chooses time. It is probably faster, because it doesn't have to check every row twice, but it uses more memory, because it puts somewhere a list of the non-empty indexes.
I went for all rows until you find an row with all null values:
Needs some clean up and will obviously remove non-null rows that occur after the first all null row. The requirement wasn't too clear here
EDIT: Just seen the comment clarifying requirement to remove all null rows - I've tweaked the below to avoid downvotes but a more comprehensive answer is already accepted (and is more efficient) :)
void Main()
{
string[,] options = new string[100,3];
options[0,0] = "bleb";
options[1,1] = "bleb";
options[2,0] = "bleb";
options[2,1] = "bleb";
options[3,2] = "bleb";
options[4,1] = "bleb";
string[,] trimmed = TrimNullRows(options);
Console.WriteLine(trimmed);
}
public string[,] TrimNullRows(string[,] options)
{
IList<string[]> nonNullRows = new List<string[]>();
for (int x = 0; x < options.GetLength(0); x++)
{
bool allNull = true;
var row = new string[options.GetLength(1)];
for (int y = 0; y < options.GetLength(1); y++)
{
row[y] = options[x,y];
allNull &= options[x,y] == null;
}
if (!allNull)
{
nonNullRows.Add(row);
}
}
var optionsTrimmed = new string[nonNullRows.Count, options.GetLength(1)];
for (int i=0;i<nonNullRows.Count;i++)
{
for (int j=0;j<options.GetLength(1);j++)
{
optionsTrimmed[i, j] = nonNullRows[i][j];
}
}
return optionsTrimmed;
}
You can also get yourself some helpers to convert between jagged and multi-dimensional representations. This is pretty silly, of course, but for arrays as small as the ones you're showing (and also, very sparse arrays), it'll be fine.
void Main()
{
string[,] options = new string[100,3];
options[3, 1] = "Hi";
options[5, 0] = "Dan";
var results =
options
.JagIt()
.Where(i => i.Any(j => j != null))
.UnjagIt();
results.Dump();
}
static class Extensions
{
public static IEnumerable<IEnumerable<T>> JagIt<T>(this T[,] array)
{
for (var i = 0; i < array.GetLength(0); i++)
yield return GetRow(array, i);
}
public static IEnumerable<T> GetRow<T>(this T[,] array, int rowIndex)
{
for (var j = 0; j < array.GetLength(1); j++)
yield return array[rowIndex, j];
}
public static T[,] UnjagIt<T>(this IEnumerable<IEnumerable<T>> jagged)
{
var rows = jagged.Count();
if (rows == 0) return new T[0, 0];
var columns = jagged.Max(i => i.Count());
var array = new T[rows, columns];
var row = 0;
var column = 0;
foreach (var r in jagged)
{
column = 0;
foreach (var c in r)
{
array[row, column++] = c;
}
row++;
}
return array;
}
}
The JagIt method is pretty simple of course - we'll just iterate over the rows, and yield the individual items. This gives us an enumerable of enumerables, which we can use in LINQ quite easily. If desired, you could transform those into arrays, of course (say, Select(i => i.ToArray()).ToArray()).
The UnjagIt method is a bit more talkative, because we need to create the target array with the correct dimensions first. And there's no unyield instruction to simplify that :D
This is pretty inefficient, of course, but that isn't necessarily a problem. You could save yourself some of the iterations by keeping the inner enumerable an array, for example - that will save us having to iterate over all the inner items.
I'm mostly keeping this as the memory-cheap, CPU-intensive alternative to #xanatos' memory-intensive, CPU-cheap (relatively).
Of course, the main bonus is that it can be used to treat any multi-dimensional arrays as jagged arrays, and convert them back again. General solutions usually aren't the most efficient :D
Yet another variant with linq
static string[,] RemoveNotNullRow(string[,] o)
{
var rowLen = o.GetLength(1);
var notNullRowIndex = (from oo in o.Cast<string>().Select((x, idx) => new { idx, x })
group oo.x by oo.idx / rowLen into g
where g.Any(f => f != null)
select g.Key).ToArray();
var res = new string[notNullRowIndex.Length, rowLen];
for (int i = 0; i < notNullRowIndex.Length; i++)
{
Array.Copy(o, notNullRowIndex[i] * rowLen, res, i * rowLen, rowLen);
}
return res;
}
I have a 2D array of floats and I want to convert it into 1D array of strings, where each string is one row of elements from 2D array. I am not getting output in text file as I expected. Can anyone tell me what I'm doing wrong? It will be great help to me, if somebody could provide efficient code with corrections.
string[] set = new string[240];
string value = "#"
for (int i = 0; i < 240; i++)
{
for (int j = 0; j < 320; j++)
{
value = Convert.ToString(ImageArray[i, j]);
value += ",";
}
set[i] = value + Environment.NewLine;
value = " ";
}
for(int k=0;k<240;k++)
{
System.IO.File.AppendAllText(#"C:\Users\mtech\Desktop\sathya.txt", set[k]);
textBlock1.Text = set[k];
value = " ";
}
inside your inner for loop(j), you are overwriting the value of value variable.
i.e.
for (int j = 0; j < 320; j++)
{
value = Convert.ToString(ImageArray[i, j]);
value += ",";
}
instead of above, you should be doing:
for (int j = 0; j < 320; j++)
{
value += Convert.ToString(ImageArray[i, j]) +",";
}
also, you don't need to perform two nested loops for this task, take a look at String.Join
Here is the shorter way with LINQ:
var allValues = ImageArray.OfType<float>();
string[] lines = new string[240];
for(int i=0; i<240; i++)
{
lines[i] = string.Join(",", allValues.Skip(i*320).Take(320));
}
File.AppendAllLines(#"C:\Users\mtech\Desktop\sathya.txt", lines);
You're re-assigning value in every iteration in your nested for loop. Use the += operator, instead. Another thing you should consider is the use of StringBuilder if you're going to repeatedly append to a string. strings are immutable so you're actually creating a new string every time you append to it.
Not sure if this applies to your case (because of the boundaries in your for loops), but you can use LINQ to flatten a multidimensional array. Example:
float[,] arr = new float[2,2]
{
{123.48F, 45.3F},
{954.23F, 91.3F}
};
var str = string.Join("",
arr.Cast<float>()
.Select(x => Convert.ToString(x) + ","));
I have a function that takes a string and returns a string. In it, I convert the string into an integer array and later try to multiply every other number like this:
private string addEveryOther(string x)
{
int[] d = x.Select(n => Convert.ToInt32(n)).ToArray();
for(int i = 0; i < 10; i++)
{
d[i] = d[i] * 2;
MessageBox.Show(d[i].ToString()); //Display the result?
i++;
}
// And later returning a string:
StringBuilder g = new StringBuilder();
foreach (int n in d)
{
g.Append(Convert.ToChar(n));
}
return g.ToString();
}
This works with addition, but not with multiplication as it returns strange values. If I input "3434343434" i expect it to return "6464646464". Now it returns: "f4f4f4f4f4" and I don't know why? Any suggestions how to go about it?
Based on the discussions above, I suppose your method should use ToString instead of Convert.ToChar.
private string addEveryOther(string x)
{
int[] d = x.Select(n => Convert.ToInt32(n.ToString())).ToArray();
for(int i = 0; i < d.Length; i += 2)
{
d[i] = d[i] * 2;
MessageBox.Show(d[i].ToString()); //Display the result?
}
// And later returning a string:
return String.Concat(d.Select(n => n.ToString()));
}
EDIT: Using #Kirill's Concat solution and #Reniuz comment in the addEveryOther method should hopefully solve the problem.
As I wrote in comment Convert.ToInt32(char)
Converts the value of the specified Unicode character to the
equivalent 32-bit signed integer.
So when you converting "0" result will be 48, when "1" result 50 and so on.
Here's changed code:
private string addEveryOther(string x)
{
//1. Convert string to int, not char to int
int[] d = x.Select(n => Convert.ToInt32(n.ToString())).ToArray();
//2. start from second number
for (int i = 1; i < 10; i++)
{
d[i] = d[i] * 2;
MessageBox.Show(d[i].ToString()); //Display the result?
i++;
}
string s = d.ToString();
// And later returning a string:
StringBuilder g = new StringBuilder();
foreach (int n in d)
{
//3. Convert int to string, not to char
g.Append(n.ToString());
}
return g.ToString();
}
Try this:
int[] d = x.Select(n => int.Parse(n.ToString())).ToArray();
for(int i = 0; i < 10; i++)
{
d[i] = (i%2 == 0? d[i] * 2 : d[i]);
}
StringBuilder g = new StringBuilder();
foreach (int n in d)
{
g.Append(n);
}
return g.ToString();
hope it helps
When you use
Convert.ToInt32(n.ToString())
There is redundant conversion. I think the simplest way is
var d = x.Select(n => Char.IsDigit(n) ? n - '0' : 0).ToArray();
I'm looking to assess similarity (including case) between two strings and give a value between 0 and 1.
I tried the Levenshtein distance implementation but it only gives integers and does not compare inner alphabets.
For e.g. comparing "ABCD" and "Abcd" gives distance of 3 and "AOOO" also gives a distance of 3 but clearly "Abcd" is better match than "AOOO".
So compared to "ABCD" I want "ABcd" to be most similar then "Abcd" then "AOOO" then "AOOOO"
I've also looked here but I am not looking for a variable length algorithm.
Thanks
Try something like this
double d = (LevenshteinDist(s, t) + LevenshteinDist(s.ToLower(), t.ToLower())) /
2.0 * Math.Max(s.Length, t.Length);
If you want to give less importance to case differences than letter differences, you can give different weights to the terms
double d = (0.15*LevenshteinDist(s, t) +
0.35*LevenshteinDist(s.ToLower(), t.ToLower())) /
Math.Max(s.Length, t.Length);
Note that the weights sum up to 0.5, thus makting the division by 2.0 obsolete.
Adapt Levenshtein Distance with a custom table T. Let the cost of insertion = 1. The cost of deletion also 1. Let T(c,d) denote the penalty of replacing c with d. T(c,c) should be = 0. T(c,d) should be <= 2.
Define Max(n,m) be the maximum theoretical distance of strings of length n and m. Obviously, Max(n,m) = n+m.
Define Distance(s,t) be the cost of changing s to t divided by Max(s,t). There you go.
Be careful in defining T so that the definition obeys distance axioms:
Distance(s,s) = 0
Distance(s,t) = Distance(t,s)
Distance(s,t) <= Distance(s,u) + Distance(u,t)
Then it will be more useful in more situations.
bool check(string[] a, string s)
{
for (int i = 0; i < a.Length; i++)
if (s == a[i])
return true;
return false;
}
public double simi(string string1, string string2)
{
int sub1 = 0;
int sub2 = 0;
string[] sp1 = new string[string1.Length - 1];
string[] sp2 = new string[string2.Length - 1];
string[] sp3 = new string[string1.Length - 1];
string[] sp4 = new string[string2.Length - 1];
for (int i = 0; i < string1.Length - 1; i++)
{
string x = "";
x = string1.Substring(i, 2);
sp1[sub1] = x;
++sub1;
}
for (int i = 0; i < string2.Length - 1; i++)
{
string x = "";
x = string2.Substring(i, 2);
sp2[sub2] = x;
++sub2;
}
int j = 0, k = 0;
for (int i = 0; i < sp1.Length; i++)
if (check(sp3, sp1[i]) == true)
{
continue;
}
else
{
sp3[j] = sp1[i];
j++;
}
for (int i = 0; i < sp2.Length; i++)
if (check(sp4, sp2[i]) == true)
{
continue;
}
else
{
sp4[k] = sp2[i];
k++;
}
Array.Resize(ref sp3, j);
Array.Resize(ref sp4, k);
Array.Sort<string>(sp3);
Array.Sort<string>(sp4);
int n = 0;
for (int i = 0; i < sp3.Length; i++)
{
if (check(sp4, sp3[i]))
{
n++;
}
}
double resulte;
int l1 = sp3.Length;
int l2 = sp4.Length;
resulte = ((2.0 * Convert.ToDouble(n)) / Convert.ToDouble(l1 + l2)) * 100;
return resulte;
}
I've read lots of posts about sorting a 2D array but I still can't master it so I was wondering if anyone can offer me some advice...
I have an aray which lists letters and quantity (I'm doing a frequency anaysis on a piece of text). I've read this data into a rectangle array and need to order it by highest frequency first. Here's my code so far:
//create 2D array to contain ascii code and quantities
int[,] letterFrequency = new int[26, 2];
//fill in 2D array with ascaii code and quantities
while (asciiNo <= 90)
{
while ((encryptedText.Length - 1) > counter)
{
if (asciiNo == (int)encryptedText[index])
{
letterCount++;
}
counter++;
index++;
}
letterFrequency[(storeCount), (0)] = (char)(storeCount+66);
letterFrequency[(storeCount), (1)] = letterCount;
storeCount++;
counter=0;
index=0;
letterCount = 0;
asciiNo++;
}
You are using a 2D array to represent 2 separate vectors - the symbols and the counts. Instead, use 2 separate arrays. Array.Sort has an overload that takes 2 arrays, and sorts on one array, but applies the changes to both, achieving what you want.
This would also allow you to use a char[] for the characters rather than int[]:
char[] symbols = ...
int[] counts = ...
...load the data...
Array.Sort(counts, symbols);
// all done!
At this
point, the counts have been ordered, and the symbols will still match index-by-index with the count they relate to.
You can wrap letter-count pair in a struct and use linq methods to manipulate data:
struct LetterCount {
public char Letter { get; set; }
public int Count { get; set; }
}
Sorting by count will look like this:
List<LetterCount> counts = new List<LetterCount>();
//filling the counts
counts = counts.OrderBy(lc => lc.Count).ToList();
public static void Sort2DArray<T>(T[,] matrix)
{
var numb = new T[matrix.GetLength(0) * matrix.GetLength(1)];
int i = 0;
foreach (var n in matrix)
{
numb[i] = n;
i++;
}
Array.Sort(numb);
int k = 0;
for (i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = numb[k];
k++;
}
}
}
Alternative approach:
var counts = new Dictionary<char,int>();
foreach(char c in text) {
int count;
counts.TryGetValue(c, out count);
counts[c] = count + 1;
}
var sorted = counts.OrderByDescending(kvp => kvp.Value).ToArray();
foreach(var pair in sorted) {
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
(untested)
In this case I'd choose to make use of KeyValuePair<TKey, TValue> and instead use something like this:
//create 2D array to contain ascii code and quantities
KeyValuePair<char, int>[] letterFrequency = new KeyValuePair<char, int>[26];
//fill in 2D array with ascaii code and quantities
while (asciiNo <= 90)
{
while ((encryptedText.Length - 1) > counter)
{
if (asciiNo == (int)encryptedText[index])
{
letterCount++;
}
counter++;
index++;
}
letterFrequency[storeCount] = new KeyValuePair<char, int>((char)(storeCount+66), letterCount);
storeCount++;
counter=0;
index=0;
letterCount = 0;
asciiNo++;
}
Then use Array.Sort:
Array.Sort(letterFrequency, (i1, i2) => i2.Value.CompareTo(i1.Value));
This'll sort a two dimension array, the bool specifies if it's sorted on the second dimension, but default it sorts on the first dimension.
void SortDoubleDimension<T>(T[,] array, bool bySecond = false)
{
int length = array.GetLength(0);
T[] dim1 = new T[length];
T[] dim2 = new T[length];
for (int i = 0; i < length; i++)
{
dim1[i] = array[i, 0];
dim2[i] = array[i, 1];
}
if (bySecond) Array.Sort(dim2, dim1);
else Array.Sort(dim1, dim2);
for (int i = 0; i < length; i++)
{
array[i, 0] = dim1[i];
array[i, 1] = dim2[i];
}
}
Why are you storing the character? You can infer it from the array index and do not need to store it! Use a one-dimensional array instead.
string encryptedText = "Test".ToUpper();
int[] frequency = new int[26];
foreach (char ch in encryptedText) {
int charCode = ch - 'A';
frequency[charCode]++;
}
var query = frequency
.Select((count, index) => new { Letter = (char)(index + 'A'), Count = count })
.Where(f => f.Count != 0)
.OrderByDescending(f => f.Count)
.ThenBy(f => f.Letter);
foreach (var f in query) {
Console.WriteLine("Frequency of {0} is {1}", f.Letter, f.Count);
}