I have two list that I convert them to a single two dimesnional array like this:
double[,] data = new double[voltage.Count(), 2];
for (int i = 0; i < voltage.Count(); i++)
{
data[i, 0] = voltage[i];
data[i, 1] = current[i];
}
Now I am trying to itterate through this array but what I get is same value for both voltage and current in each line:
foreach (double data in ztr.GetCurveDataForTestType()) //this will return my array
{
richTextBox1.AppendText("Voltage" + data + " --------- ");
richTextBox1.AppendText("Current" + data + "\r\n");
}
Voltage-0.175 --------- Current-0.175
Voltage-9.930625E-06 --------- Current-9.930625E-06
Voltage-0.171875 --------- Current-0.171875
Voltage-9.53375E-06 --------- Current-9.53375E-06
Voltage-0.16875 --------- Current-0.16875
As you see in the first line both voltage and current are same value that is voltage, and on the second raw they are the same again but this time it is the current value. How can I fix this?
I'd recommend not using multi-dimensional arrays for this.
Instead you can make a class something like this:
class Measurement
{
public double Voltage { get; set; }
public double Current { get; set; }
}
And change your method to return IEnumerable<Measurement>. In .NET 4.0 you can use Zip:
public IEnumerable<Measurement> GetCurveDataForTestType()
{
return voltage.Zip(current,
(v, c) => new Measurement { Voltage = v, Current = c});
}
And for older versions of .NET:
public IEnumerable<Measurement> GetCurveDataForTestType()
{
for (int i = 0; i < voltage.Count(); i++)
{
yield return new Measurement
{
Voltage = voltage[i],
Current = current[i]
};
}
}
Then your code becomes:
foreach (Measurement data in ztr.GetCurveDataForTestType())
{
richTextBox1.AppendText(
"Voltage: {0} --------- Current: {1}", data.Voltage, data.Current);
}
You use the same kind of loop as when you created the array:
for (int i = 0; i < data.GetLength(0); i++) {
richTextBox1.AppendText("Voltage" + data[i, 0] + " --------- ");
richTextBox1.AppendText("Current" + data[i, 1] + "\r\n");
}
Update:
This question appears to be a duplicate of How to foreach through a 2 dimensional array?. The linked answer has an alternate solution that enables the use of foreach by switching from a two-dimensional array to an array of array.
foreach with a two dimensional array, will sequentially return every double value in the array (by design).
For example, given the following two-dimensional array of doubles:
var array = new double[,] { { 0, 1, }, { 2, 3 }, { 4, 5 } };
foreach (var d in array)
{
Console.WriteLine(d);
}
You will get the following Console output:
0
1
2
3
4
5
Therefore, foreach is not appropriate for you needs. You should use a for loop.
Related
I'm trying to write code that makes a union between array a and b (AUB), but when I want to print the combined array. the console prints System.Int32\[\].
For context, if my
array a = { 1, 3, 5, 6 }
and my
array b = { 2, 3, 4, 5 }
my union array should be
combi = { 1, 2, 3, 4, 5, 6 }
but like I said, combi prints out as System.Int32\[\]
I don't know if it's the way I'm doing the union or if its the way I'm printing it. I'm also trying to do a
A intersection B and A – B
But I haven't tried anything of those yet, I would appreciate if you have any tips.
using System;
using System.Reflection.Metadata.Ecma335;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("size of A? ");
int a = Convert.ToInt32(Console.In.ReadLine());
Console.WriteLine("Value of A:");
int[] ans = new int[a];
for (int i = 0; i < ans.Length; i++)
{
ans[i] = Convert.ToInt32(Console.In.ReadLine());
}
Console.WriteLine("size of B?");
int b = Convert.ToInt32(Console.In.ReadLine());
Console.WriteLine("Value of B:");
int[] anse = new int[b];
for (int i = 0; i < anse.Length; i++)
{
anse[i] = Convert.ToInt32(Console.In.ReadLine());
}
var combi = new int[ans.Length + anse.Length];
for (int i = 0; i < combi.Length; i++)
{
Console.WriteLine(combi + " ");
}
Console.ReadLine();
}
}
}
when i want to print the combined array the console prints
System.Int32[]
If you write Console.Write(someObject), the method tries to find an overridden ToString in someObject. If there is none System.Object.ToString is used which just returns the fully qualified name of the type of the Object, which is "System.Int32[]" in case of an int[].
If you want to print out an array of integers one approach would be to use string.Join:
string spaceSeparatedList = string.Join(" ", combi);
Now you have a space-separated list of integers.
In the code You have just initialized the size of the array of Combi Array not assign the values
First you have to add Array a and Array b values into combi array
Then try to print into union,see below code for the reference:
List<int> combi = new List<int>();
foreach(var first in ans)
{
combi.Add(first);
}
foreach (var second in anse)
{
combi.Add(second);
}
combi.Sort();
string result = string.Join(",",combi);
Console.WriteLine(result);
I am trying to join the next array element together to single element from array if the element of the array is less than length 4. It should add to the next element index.
Another logic is, if the next consecutive array length is also less then 4 char then it joins the next array element also up to 3 times in total. I want to implement this. It's getting complex for me I am not understand this logic.
This is the code, here it has array on titleList, now we have to use the above logic in this array list.
#foreach (var title in randomtitle)
{
</span>#titleList.ElementAt(title)</span>
}
#code {
[Parameter]
public string theTitle { get; set; }
private string[] titleList = Array.Empty<string>();
protected override void OnParametersSet()
{
if (!string.IsNullOrEmpty(theTitle))
{
titleList = theTitle.Split(" ");
}
}
private Random random = new();
private IEnumerable<int> randomtitle =>
Enumerable.Range(0, titleList.Count() - 1) // { 0, 1, 2, 3 } generate sequence
.OrderBy(x => random.Next()) // { 3, 1, 0, 2 } random shuffle
.Take(2) // { 3, 1 } pick two
.ToList();
}
I think you are looking for a method that does following:
take a collection of strings(like a string[])
iterate each string and check if it's length is greater than or equal 4
if so, everything is fine, take it as it is
if not, append the next to the current string and check their length afterwards
if they are still not greater than or equal 4 append the next one, but max 3 times
Then this should work (not tested well though):
Demo: https://dotnetfiddle.net/2uHREv
static string[] MergeItems(IList<string> all, int minLength, int maxGroupCount)
{
List<string> list = new List<string>(all.Count);
for(int i = 0; i < all.Count; i++)
{
string current = all[i];
if(i == all.Count - 1)
{
list.Add(current);
break;
}
if (current.Length < minLength)
{
for (int ii = 1; ii < maxGroupCount && i + ii < all.Count; ii++)
{
int nextIndex = i + ii;
string next = all[nextIndex];
current = current + next;
if (current.Length >= minLength || ii+1 == maxGroupCount)
{
list.Add(current);
i = nextIndex;
break;
}
}
}
else
{
list.Add(current);
}
}
return list.ToArray();
}
My textfile contains contents such as:
1/1/2018;0;29;10
1/2/2018;0;16;1
1/3/2018;0;32;1
1/4/2018;0;34;15
1/5/2018;0;19;2
1/6/2018;0;21;2
Further down in the textfiles are decimals which is why I am trying to use double
1/29/2018;0.32;52;38
1/30/2018;0.06;44;21
I am trying to split up the semicolons and assign each value between the semicolons into a 2D array that contains 31 rows and 4 columns.
private void button1_Click(object sender, EventArgs e)
{
// 2d array
double[,] testarray = new double[31, 4];
string inputFile = File.ReadAllText("testywesty.txt");
char[] spearator = {';',' '};
for (int row = 0; row < 31; row++)
{
for (int column = 0; column < 4; column++)
{
string[] strlist = inputFile.Split(spearator);
testarray [row,column] = double.Parse(strlist[column]);
}
}
}
I believe that I have the right loop needed to insert my values into the 2d array, however, I am getting an error for my input and I believe it is because of the slashes.
Is my code sufficient for holding the text file's contents into my array? And how do I deal with the '/' characters?
You'd be getting an error on the slashes because you're trying to convert them to doubles, which is not possible. One thing you can do is first convert them to a DateTime using the Parse method of that class, and then use the ToOADate method to convert it to a double. Note that if you need to convert it back, you can use the DateTime.FromOADate method as I've done in the output below.
Also, it might be helpful to use File.ReadAllLines to read the file into an array of strings, where each string is a file line (this assumes that each line contains the four parts you need as you've shown in the sample file contents in the question). This way each line represents a row, and then we can split that line to get our columns.
For example:
private static void button1_Click(object sender, EventArgs e)
{
var lines = File.ReadAllLines("testywesty.txt");
var items = new double[lines.Length, 4];
var delims = new[] {';', ' '};
for (var line = 0; line < lines.Length; line++)
{
var parts = lines[line].Split(delims);
var maxParts = Math.Min(parts.Length, items.GetLength(1));
for (var part = 0; part < maxParts; part++)
{
if (part == 0)
{
// Parse first item to a date then use ToOADate to make it a double
items[line, part] = DateTime.Parse(parts[part]).ToOADate();
}
else
{
items[line, part] = double.Parse(parts[part]);
}
}
}
// Show the output
var output = new StringBuilder();
for (var row = 0; row < items.GetLength(0); row++)
{
var result = new List<string>();
for (var col = 0; col < items.GetLength(1); col++)
{
result.Add(col == 0
? DateTime.FromOADate(items[row, col]).ToShortDateString()
: items[row, col].ToString());
}
output.AppendLine(string.Join(", ", result));
}
MessageBox.Show(output.ToString(), "Results");
}
Output
Of course, you can read the data and parse it into an array. But since it is polymorphic the array needs to be of object[,] type. This is how I would approach this:
class Program
{
static void Main(string[] args)
{
object[,] array = ReadFileAsArray("testywesty.txt");
}
static object[,] ReadFileAsArray(string file)
{
// how long is the file?
// read it twice, once to count the rows
// and a second time to read each row in
int rows = 0;
var fs = File.OpenText(file);
while (!fs.EndOfStream)
{
fs.ReadLine();
rows++;
}
fs.Close();
var array = new object[rows, 4];
fs = File.OpenText(file);
int row = 0;
while (!fs.EndOfStream)
{
// read line
var line = fs.ReadLine();
// split line into string parts at every ';'
var parts = line.Split(';');
// if 1st part is date store in 1st column
if (DateTime.TryParse(parts[0], out DateTime date))
{
array[row, 0] = date;
}
// if 2nd part is flaot store in 2nd column
if (float.TryParse(parts[1], out float x))
{
array[row, 1] = x;
}
// if 3rd part is integer store in 3rd column
if (int.TryParse(parts[2], out int a))
{
array[row, 2] = a;
}
// if 4rd part is integer store in 4rd column
if (int.TryParse(parts[3], out int b))
{
array[row, 3] = b;
}
row++;
}
fs.Close();
return array;
}
}
But I feel this is clunky. If the data types represented by the file are predetermined than filling in a collection of a custom type feels more natural in C#, as you let the type handle its own data and parsing. Consider the example below:
class Program
{
static void Main(string[] args)
{
IEnumerable<MyData> list = ReadFileAsEnumerable("testywesty.txt");
Debug.WriteLine(MyData.ToHeading());
foreach (var item in list)
{
Debug.WriteLine(item);
}
// date x a b
// 1/1/2018 0 29 10
// 1/2/2018 0 16 1
// 1/3/2018 0 32 1
// 1/4/2018 0 34 15
// 1/5/2018 0 19 2
// 1/6/2018 0 21 2
// 1/29/2018 0.32 52 38
// 1/30/2018 0.06 44 21
}
public static IEnumerable<MyData> ReadFileAsEnumerable(string file)
{
var fs = File.OpenText(file);
while (!fs.EndOfStream)
{
yield return MyData.Parse(fs.ReadLine());
}
fs.Close();
}
}
/// <summary>
/// Stores a row of my data
/// </summary>
/// <remarks>
/// Mutable structures are evil. Make all properties read-only.
/// </remarks>
public struct MyData
{
public MyData(DateTime date, float number, int a, int b)
{
this.Date = date;
this.Number= number;
this.A=a;
this.B=b;
}
public DateTime Date { get; }
public float Number { get; }
public int A { get; }
public int B { get; }
public static MyData Parse(string line)
{
// split line into string parts at every ';'
var parts = line.Split(';');
// if 1st part is date store in 1st column
if (DateTime.TryParse(parts[0], out DateTime date)) { }
// if 2nd part is flaot store in 2nd column
if (float.TryParse(parts[1], out float number)) { }
// if 3rd part is integer store in 3rd column
if (int.TryParse(parts[2], out int a)) { }
// if 4rd part is integer store in 4rd column
if (int.TryParse(parts[3], out int b)) { }
return new MyData(
date,
number,
a,
b);
}
public static string ToHeading()
{
return $"{"date",-11} {"x",-4} {"a",-4} {"b",-4}";
}
public override string ToString()
{
return $"{Date.ToShortDateString(),-11} {Number,4} {A,4} {B,4}";
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have a list of object. Those objects contain lat and lon coordinates among other properties. I want to extract only thoose coordonates that satisfy
(Math.Abs(elem1.lat - elem2.lat) > Delta && Math.Abs(elem1.lon - elem2.lon) > Delta)
Basically I want to extract only objects that dont have coordinates close to each other.
Is there an elegant way to do this with C# LINQ ?
EDIT 1 :
So elem1 and elem2 are any 2 elements from the list. I elements that will result from the query to have more then delta between any 2 of them
EDIT 2 :
This is my code at the moment. It works as I want :
for (int i = 0; i < companyHistory.Count; i++)
{
var isOk = true;
var count = zoomApprovedHistory.Count;
for (var j = 0; j < count; j++)
{
if (Math.Abs(companyHistory[i].X - zoomApprovedHistory[j].X) < delta && Math.Abs(companyHistory[i].Y - zoomApprovedHistory[j].Y) < delta)
{
isOk = false;
break;
}
}
// if no other point is close add it to approved array for this zoom
if (isOk)
{
zoomApprovedHistory.Add(companyHistory[i]);
}
}
How can I optimize it ? it has O(n^2) complexity. Looking for the fastest option
Your question is not well-phrased. If your elem1 or elem2 is a single item you want to compare against, this is pretty easy. Just do a LINQ Where to find the items that match the criteria.
Coordinates it = new Coordinates { lat = 5, lon = 5 };
var picked = list.Where(x => Math.Abs(x.lat - it.lat) < Delta && Math.Abs(x.lon - it.lon) < Delta);
If, on the other hand, your two elements are any two elements in the list, then you run into a problem where you need to clarify things. As I mentioned in my comment, if your have elem1, elem2, and elem3, and if the first two don't match the criteria but if elem2 and elem3 do match the criteria, then are both of those elements (2 and 3) 'hits'? Assuming they are, the solution below will work. I wrote a simple Comparer to help make things easy as well.
public class CoordinateComparer : IEqualityComparer<Coordinates>
{
public bool Equals(Coordinates x, Coordinates y)
{
return (x.lat == y.lat && x.lon == y.lon);
}
public int GetHashCode(Coordinates obj)
{
unchecked
{
int hash = 17;
if (obj != null)
{
hash = hash * 23 + obj.lat.GetHashCode();
hash = hash * 23 + obj.lon.GetHashCode();
}
return hash;
}
}
}
public class Coordinates
{
public int lat { get; set; }
public int lon { get; set; }
}
class MainClass
{
public static void Main(string[] args)
{
List<Coordinates> list = new List<Coordinates>();
list.Add(new Coordinates { lat = 5, lon = 4 });
list.Add(new Coordinates { lat = 4, lon = 5 });
list.Add(new Coordinates { lat = 7, lon = 4 });
list.Add(new Coordinates { lat = 6, lon = 3 });
list.Add(new Coordinates { lat = 8, lon = 2 });
double Delta = 1.1;
List<Coordinates> results = new List<Coordinates>();
foreach(Coordinates item in list)
{
// Find items that match the condition
var matches = list.Where(x => Math.Abs(x.lat - item.lat) < Delta && Math.Abs(x.lon - item.lon) < Delta);
// The 'item' will always match the condition with itself, which is undesirable, so remove it
matches = matches.Except(new List<Coordinates> { item }, new CoordinateComparer());
// Add the items that are not already in it to the results list
results.AddRange(matches.Where(x => !results.Contains(x, new CoordinateComparer())));
}
foreach (Coordinates item in results)
Console.WriteLine("Lat : {0}, Lon : {1}", item.lat, item.lon);
Console.ReadLine();
}
}
Bear in mind that if your latitude and longitude coordinates are either double or float, which they probably are, you might run into problems when comparing. But that's an altogether different question.
For a school project in learning c# I am making a data collection console application which saves floating point entries for 4 different locations along with the time/date, and user who recorded the entry. I am required to use a multi dimensional struct array.
I need to have a view that displays the average of the values, along with the minimum and maximum values and the first and last date. I've got the average figured out by counting through the values and adding cumulatively but I can't figure out how to find the minimum and maximum values.
I tried searching and came across this page: http://www.dotnetperls.com/max
I tried to implement this syntax into my code to no avail due to it being a much more complex array.
It worked in my test with integers:
class Program
{
static int[][] intarray = new int[4][] { new int[10], new int[10], new int[10], new int[10] };
static void Main(string[] args)
{
intarray[0][0] = 5;
intarray[0][1] = 3;
intarray[0][2] = 10;
intarray[0][3] = 4;
intarray[0][4] = 2;
Console.WriteLine(intarray[0].Max());
Console.ReadLine();
}
}
The above code perfectly displays the number 10! :)
But when I tried to implement this in to my program with a struct array, it doesn't work:
class Program
{
static byte location = 0;
static float entriesmin;
static float entriesmax;
static Entry[][] entriesarray = new Entry[4][] { new Entry[10], new Entry[10], new Entry[10], new Entry[10] };
struct Entry
{
public float value;
public string user;
public DateTime datetime;
}
static byte LoopEntries(bool display)
{
float runningtotal = 0;
byte entrycount = 0;
foreach (Entry entry in entriesarray[0])
{
if (entry.user != null)
{
if (display)
{
string ten;
if (entrycount == 9)
{
ten = " #";
}
else
{
ten = " #";
}
Console.WriteLine(ten + (entrycount + 1) + " " + entry.datetime + " " + entry.user + new string(' ', 16 - entry.user.Length) + entry.value);
}
runningtotal += entry.value;
entrycount += 1;
}
}
entriesmin = (entriesarray[location]).value.Min();
entriesmax = (entriesarray[location]).value.Max();
if (entrycount == 0 && display)
{
Console.WriteLine("No entries to show!");
}
return entrycount;
}
I need to hand this project in on Monday! I really hope someone can help me! ;)
What you have is not a multidimensional array, it's an array of array (a.k.a. a jagged array), but you work with them in a similar way.
To loop through the array of arrays you need a loop in a loop:
foreach (Entry[] arr in entriesarray) {
foreach (Entry entry in arr) {
// ...
}
}
You could use the Min and Max extension methods to get the minimum and maximum value of each inner array, but you still would have to find the minimum and maximum between those values. As you are already looping through all the entries anyway to get the average you can just keep a record of the smallest and largest values found:
float runningtotal = 0;
int entrycount = 0;
float min = float.MaxValue;
float max = float.MinValue;
foreach (Entry[] arr in entriesarray) {
foreach (Entry entry in arr) {
runningtotal += entry.value;
entrycount++;
if (entry.value < min) {
min = entry.value;
}
if (entry.value > max) {
max = entry.value;
}
}
}