I'm trying to print out a list of phone numbers (\n for each number) in a format {type}:{number}. So from a list of 2 numbers I would print out:
Home: 111-111-1111
Cell: 222-222-2222
So far I can select into an anonymous type but when I go to aggregate it is leterally printing out the whole anonymous type on the screen looking exactly like below:
new { phoneType = Home + ": ", phoneNumber = 111-111-1111 }
Should I even be using aggregate?
This is what I'm working with:
PhoneNumbers.Select(x => new { phoneType = x.PhoneType, phoneNumber = x.PhoneNumber1 }).Aggregate(
(p, x) => new { phoneType = p.phoneType + ": ", x.phoneNumber });
If you just want the phone numbers as strings, you can create that string in a Select call:
var x = PhoneNumbers.Select(x => string.Format("{0}: {1}", x.PhoneType, x.PhoneNumber));
Your Aggregate call is basically a bug (assuming it even compiles) because you're combining the "current" phone number with the previous phone type. It's also unnecessary for combining the phone numbers as text because of existing string methods:
var phoneNumberStrings = PhoneNumbers.Select(x => string.Format("{0}: {1}", x.PhoneType, x.PhoneNumber));
var text = string.Join(Environment.NewLine, phoneNumberStrings);
While you could do this with IEnumerable<string>.Aggregate, I feel it's cleaner if you just use string.Join. Someone reading your code will be able to more easily get the meaning out if they see "join these strings with newline."
string.Join(
Environment.NewLine,
PhoneNumbers.Select(x =>
string.Format("{0}: {1}", x.PhoneType, x.PhoneNumber));
Related
My program creates a .csv file with a persons name and an integer next to them.
Occasionally there are two entries of the same name in the file, but with a different time. I only want one instance of each person.
I would like to take the mean of the two numbers to produce just one row for the name, where the number will be the average of the two existing.
So here Alex Pitt has two numbers. How can I take the mean of 105 and 71 (in this case) to produce a row that just includes Alex Pitt, 88?
Here is how I am creating my CSV file if reference is required.
public void CreateCsvFile()
{
PaceCalculator ListGather = new PaceCalculator();
List<string> NList = ListGather.NameGain();
List<int> PList = ListGather.PaceGain();
List<string> nAndPList = NList.Zip(PList, (a, b) => a + ", " + b).ToList();
string filepath = #"F:\A2 Computing\C# Programming Project\ScheduleFile.csv";
using (var file = File.CreateText(filepath))
{
foreach (var arr in nAndPList)
{
if (arr == null || arr.Length == 0) continue;
file.Write(arr[0]);
for (int i = 1; i < arr.Length; i++)
{
file.Write(arr[i]);
}
file.WriteLine();
}
}
}
To start with, you can write your current CreateCsvFile much more simply like this:
public void CreateCsvFile()
{
var filepath = #"F:\A2 Computing\C# Programming Project\ScheduleFile.csv";
var ListGather = new PaceCalculator();
var records =
ListGather.NameGain()
.Zip(ListGather.PaceGain(),
(a, b) => String.Format("{0},{1}", a, b));
File.WriteAllLines(filepath, records);
}
Now, it can easily be changed to work out the average pace if you have duplicate names, like this:
public void CreateCsvFile()
{
var filepath = #"F:\A2 Computing\C# Programming Project\ScheduleFile.csv";
var ListGather = new PaceCalculator();
var records =
from record in ListGather.NameGain()
.Zip(ListGather.PaceGain(),
(a, b) => new { Name = a, Pace = b })
group record.Pace by record.Name into grs
select String.Format("{0},{1}", grs.Key, grs.Average());
File.WriteAllLines(filepath, records);
}
I would recommend to merge the duplicates before you put everything into the CSV file.
use:
// The List with all duplicate values
List<string> duplicateChecker = new List<string>();
//Takes the duplicates and puts them in a new List. I'm using the NList because I assume the Names are the important part.
duplicateChecker = NList .Distinct().ToList();
Now you can simply Iterrate through the new list and search their values in your NList. Use a foreach loop which is looking up the index of the Name value in Nlist. After that you can use the Index to merge the integers with a simple math method.
//Something like this:
Make a foreach loop for every entry in your duplicateChecker =>
Use Distrinc again on duplicateChecker to make sure you won't go twice through the same duplicate =>
Get the Value of the current String and search it in Nlist =>
Get the Index of the current Element in Nlist and search for the Index in Plist =>
Get the Integer of Plist and store it in a array =>
// make sure your math method runs before a new name starts. After that store the new values in your nAndPList
Once the Loop is through with the first name use a math method.
I hope you understand what I was trying to say. However I would recommend using a unique identifier for your persons. Sooner or later 2 persons will appear with the same name (like in a huge company).
Change the code below:
List<string> nAndPList = NList.Zip(PList, (a, b) => a + ", " + b).ToList();
To
List<string> nAndPList = NList.Zip(PList, (a, b) => a + ", " + b)
.ToList()
.GroupBy(x => x.[The field you want to group by])
.Select(y => y.First);
How can I get the string from a list that best match with a base string using the Levenshtein Distance.
This is my code:
{
string basestring = "Coke 600ml";
List<string> liststr = new List<string>
{
"ccoca cola",
"cola",
"coca cola 1L",
"coca cola 600",
"Coke 600ml",
"coca cola 600ml",
};
Dictionary<string, int> resultset = new Dictionary<string, int>();
foreach(string test in liststr)
{
resultset.Add(test, Ldis.Compute(basestring, test));
}
int minimun = resultset.Min(c => c.Value);
var closest = resultset.Where(c => c.Value == minimun);
Textbox1.Text = closest.ToString();
}
In this example if I run the code I get 0 changes in string number 5 from the list, so how can I display in the TextBox the string itself?
for exemple : "Coke 600ml" Right now my TextBox just returns:
System.Linq.Enumerable+WhereEnumerableIterator`1
[System.Collections.Generic.KeyValuePair`2[System.String,System.Int32]]
Thanks.
Try this
var closest = resultset.First(c => c.Value == minimun);
Your existing code is trying to display a list of items in the textbox. I looks like it should just grab a single item where Value == min
resultset.Where() returns a list, you should use
var closest = resultset.First(c => c.Value == minimun);
to select a single result.
Then the closest is a KeyValuePair<string, int>, so you should use
Textbox1.Text = closest.Key;
to get the string. (You added the string as Key and changes count as Value to resultset earilier)
There is a good solution in code project
http://www.codeproject.com/Articles/36869/Fuzzy-Search
It can be very much simplified like so:
var res = liststr.Select(x => new {Str = x, Dist = Ldis.Compute(basestring, x)})
.OrderBy(x => x.Dist)
.Select(x => x.Str)
.ToArray();
This will order the list of strings from most similar to least similar.
To only get the most similar one, simply replace ToArray() with First().
Short explanation:
For every string in the list, it creates an anonymous type which contains the original string and it's distance, computed using the Ldis class. Then, it orders the collection by the distance and maps back to the original string, so as to lose the "extra" information calculated for the ordering.
I have the following string arrays:
var myArray1 = new string[] {"A", "B", "C"};
var myArray2 = new string[] {"t1", "t2"};
I would like to be able to produce a final string that looks like this:
var myFinalString = "t1.A, t2.A, t1.B, t2.B, t1.C, t2.C";
I know I can iterate through each element of the array and build the string manually. However, I'd like to know if there's a better way. I tried to figure out how to make String.Join() method work, but couldn't :-(.
I don't know that any direct method exists, but this one-liner
return
from a in myArray
from b in tTerms
select string.Format("{0}.{1}", b, a)
should do it.
This works:
var query = from x in new[]{"A", "B", "C"}
from y in new[]{"t1", "t2"}
select y + "." + x;
var result = string.Join(", ", query.ToArray());
The term for such sequence is "Cartesian Product".
Here is long blog by Eric Lippert on it Computing a Cartesian Product with LINQ
As it is already shown in other answers sequence of tuples can be obtained with following code and than aggregated (using Join in case of string, or Aggregate for other type of result) to produce your final string:
var product =
from first in s1
from second in s2
select new[] { first, second };
var result String.Join(", ",
product.Select(p => String.Format("{0}.{1}", p.first, p.second));
If the two sequences are of the same length, you could probably put Enumerable.Zip to work for you.
var myFinalString = myArray.Zip(mySecondArray, (f, s) => f + "." + s);
I have a list of strings and I want to join them with " "(space) between them, so I use the string.Join method:
foreach (var line in lines)
{
var strings = lines.Where(l => l.Code == line.Code).Select(l => l.Data);
var original = string.Join(" ", strings);
}
Data looks something like this: "123456789, 987654321, 32132, 7873892 ..."
But I get an OutOfMemoryException. Why? each string is approximatly 100-150 characters and there are 5-10 strings in the list.
Is there a better way then the string.Join?
Try this (and let us know if you get the same error):
lines.GroupBy(l => l.Code).Select(l => string.Join(" ", l.Select (x => x.Data)));
foreach (var line in lines.GroupBy(p=>p.Code))
{
var original = string.Join(" ", line.Select(p=>p.Data));
}
The StringBuild() class can join strings and isn't immutable.
Here's an MSDN article talking about immutable string vs how StringBuilder works.
http://msdn.microsoft.com/en-us/library/2839d5h5(v=vs.71).aspx
i have an entity called Product
class Product
{
public Id { get; set; }
public Name { get; set; }
}
and i have a list of all products:
IEnumerable<Product> products = _productRepository.GetAll()
i want to get an array of strings from this list of products this array will contains the product Id + Product Name, so when i try to cast it using the following code:
string[] s = products.Cast<string>().ToArray();
i got the following exception:
Unable to cast object of type 'Product' to type 'System.String'
the exception really makes alot fo scence, so if i had a method
string ProductToString(Product p)
{
return p.Name;
}
or an override to ToString() for the product object so how i can use this method to get the list of string[] from IEnumerable ?
Well, given that method you can use1:
string[] s = products.Select<string>(ProductToString).ToArray();
However, it would be more idiomatic to do this without a separate method, usually, using a lambda expression:
// Matches ProductToString, but not your description
string[] s = products.Select(p => p.Name).ToArray();
I'd only use a separate method if it was going to be called from various places (ensuring consistency) or did a lot of work.
EDIT: I've just noticed that your description (wanting ID + name) doesn't actually match the ProductToString method you've given (which just gives the name). For the ID + name I'd use:
string[] s = products.Select(p => p.ID + " " + p.Name).ToArray();
or
string[] s = products.Select(p => string.Format("{0} {1}", p.ID, p.Name))
.ToArray();
Or you could just change your ProductToString method, of course.
Alternatively, you could override ToString() in Product, if this is usually how you want to convert a Product to a string. You could then either use a method group conversion or a lambda expression to call ToString.
1 It's possible that you don't need to specify the type argument explicitly - that:
string[] s = products.Select(ProductToString).ToArray();
will work fine - the rules for type inference and method group conversions always confuse me and the compiler behaviour has changed slightly over time. A quick test just now looks like it does work, but there could be subtleties in slightly different situations.
string[] s = products.Select(p => p.Name).ToArray();
Or, if you need Id + Name:
string[] s = products.Select(p => p.Id + ' ' + p.Name).ToArray();
use
string[] s = (from p in products select p.Id.ToString() + " " + p.Name.ToString()).ToArray();
This worked for me:
String.Join(";", mi_customer.Select(a => a.Id).Cast<string>().ToArray());
Where mi_customer must be your object, in my case is a table.