I'm quite new to using predicates for finding something specific within a collection.
Here's my example:
static void FindPersons(string firstLetter)
{
List<string> names = new List<string>()
{"Marcus", "John", "Jesse", "Lance", "Aaron", "Archibald", "Victor"
};
List<string> names2 = names.FindAll(a => a.StartsWith(firstLetter));
foreach (var name in names2)
{
Console.WriteLine(name);
}
}
I'd call the method within Main:
FindPersons("a");
I had to use string for the first letter because StartsWith takes string as a parameter (or I could use char and ToString().
How can I do this using this shorter syntax?
One more question - Generally, how often during your work you use predicates to find specific objects within a collection?
Thanks.
Just use Console.WriteLine(string.Join<string>("\n", result)); as following method to do that.
static void FindPersons(string firstLetter)
{
List<string> names = new List<string>()
{"Marcus", "John", "Jesse", "Lance", "Aaron", "Archibald", "Victor"
};
List<string> result = names.Where(a => a.StartsWith(firstLetter, StringComparison.InvariantCultureIgnoreCase)).ToList();
Console.WriteLine(string.Join<string>("\n", result));
}
Related
So I have
List<string[]> listy = new List<string[]>();
listy.add('a','1','blue');
listy.add('b','2','yellow');
And i want to search through all of the list ti find the index where the array containing 'yellow' is, and return the first element value, in this case 'b'.
Is there a way to do this with built in functions or am i going to need to write my own search here?
Relatively new to c# and not aware of good practice or all the built in functions. Lists and arrays im ok with but lists of arrays baffles me somewhat.
Thanks in advance.
As others have already suggested, the easiest way to do this involves a very powerful C# feature called LINQ ("Language INtegrated Queries). It gives you a SQL-like syntax for querying collections of objects (or databases, or XML documents, or JSON documents).
To make LINQ work, you will need to add this at the top of your source code file:
using System.Linq;
Then you can write:
IEnumerable<string> yellowThings =
from stringArray in listy
where stringArray.Contains("yellow")
select stringArray[0];
Or equivalently:
IEnumerable<string> yellowThings =
listy.Where(strings => strings.Contains("yellow"))
.Select(strings => strings[0]);
At this point, yellowThings is an object containing a description of the query that you want to run. You can write other LINQ queries on top of it if you want, and it won't actually perform the search until you ask to see the results.
You now have several options...
Loop over the yellow things:
foreach(string thing in yellowThings)
{
// do something with thing...
}
(Don't do this more than once, otherwise the query will be evaluated repeatedly.)
Get a list or array :
List<string> listOfYellowThings = yellowThings.ToList();
string[] arrayOfYellowThings = yellowThings.ToArray();
If you expect to have exactly one yellow thing:
string result = yellowThings.Single();
// Will throw an exception if the number of matches is zero or greater than 1
If you expect to have either zero or one yellow things:
string result = yellowThings.SingleOrDefault();
// result will be null if there are no matches.
// An exception will be thrown if there is more than one match.
If you expect to have one or more yellow things, but only want the first one:
string result = yellowThings.First();
// Will throw an exception if there are no yellow things
If you expect to have zero or more yellow things, but only want the first one if it exists:
string result = yellowThings.FirstOrDefault();
// result will be null if there are no yellow things.
Based on the problem explanation provided by you following is the solution I can suggest.
List<string[]> listy = new List<string[]>();
listy.Add(new string[] { "a", "1", "blue"});
listy.Add(new string[] { "b", "2", "yellow"});
var target = listy.FirstOrDefault(item => item.Contains("yellow"));
if (target != null)
{
Console.WriteLine(target[0]);
}
This should solve your issue. Let me know if I am missing any use case here.
You might consider changing the data structure,
Have a class for your data as follows,
public class Myclas
{
public string name { get; set; }
public int id { get; set; }
public string color { get; set; }
}
And then,
static void Main(string[] args)
{
List<Myclas> listy = new List<Myclas>();
listy.Add(new Myclas { name = "a", id = 1, color = "blue" });
listy.Add(new Myclas { name = "b", id = 1, color = "yellow" });
var result = listy.FirstOrDefault(t => t.color == "yellow");
}
Your current situation is
List<string[]> listy = new List<string[]>();
listy.Add(new string[]{"a","1","blue"});
listy.Add(new string[]{"b","2","yellow"});
Now there are Linq methods, so this is what you're trying to do
var result = listy.FirstOrDefault(x => x.Contains("yellow"))?[0];
I've just noticed that when you declare a List in c# you can put parentheses or curly braces at the end.
List<string> myList = new List<string>();
List<string> myList2 = new List<string>{};
Both these list appear to have the same functionality. Is there any actual difference caused by declaring them with parentheses or curly braces?
The use of curly braces { } is called a collection initializer. For types that implement IEnumerable the Add method would be invoked normally, on your behalf:
List<string> myList2 = new List<string>() { "one", "two", "three" };
Empty collection initializers are allowed:
List<string> myList2 = new List<string>() { };
And, when implementing an initializer, you may omit the parenthesis () for the default constructor:
List<string> myList2 = new List<string> { };
You can do something similar for class properties, but then it's called an object initializer.
var person = new Person
{
Name = "Alice",
Age = 25
};
And its possible to combine these:
var people = new List<Person>
{
new Person
{
Name = "Alice",
Age = 25
},
new Person
{
Name = "Bob"
}
};
This language feature introduced in C# 3.0 also supports initializing anonymous types, which is especially useful in LINQ query expressions:
var person = new { Name = "Alice" };
They also work with arrays, but you can further omit the type which is inferred from the first element:
var myArray = new [] { "one", "two", "three" };
And initializing multi-dimensional arrays goes something like this:
var myArray = new string [,] { { "a1", "b1" }, { "a2", "b2" }, ... };
Update
Since C# 6.0, you can also use an index initializer. Here's an example of that:
var myDictionary = new Dictionary<string, int>
{
["one"] = 1,
["two"] = 2,
["three"] = 3
};
They have different semantics.
List<string> myList = new List<string>();
The above line initializes a new List of Strings, and the () is part of the syntax of building a new object by calling its constructor with no parameters.
List<string> myList2 = new List<string>{};
The above line initializes a new List of Strings with the elements presented inside the {}. So, if you did List<string> myList2 = new List<string>{"elem1", "elem2"}; you are defining a new list with 2 elements. As you defined no elements inside the {}, it will create an empty list.
But why does the second line have no () ?
That makes part of a discussion in which omitting the parenthesis in this case represents a call to the default constructor. Take a look at This Link
The first version initialises an empty list. The second version is used to initialise the list with values. You wouldn't, or shouldn't, see the second version used without at least one instance of T.
So you could do something like:
List<string> Foo = new List<string>{"foo", "bar"};
or
List<T> Foo = new List<T>{SomeInstancesOfT};
This is useful in many places when initialising objects.
See https://msdn.microsoft.com/en-us/library/bb384062.aspx
To be short - there is no difference in the objects created.
But there's more:
What you are asking isn't a List specific question - it's a question of object and Collection initialization.
See here.
If We have a list of strings like the following code:
List<string> XAll = new List<string>();
XAll.Add("#10#20");
XAll.Add("#20#30#40");
string S = "#30#20";//<- this is same as #20#30 also same as "#20#30#40" means S is exist in that list
//check un-ordered string S= #30#20
// if it is contained at any order like #30#20 or even #20#30 ..... then return true :it is exist
if (XAll.Contains(S))
{
Console.WriteLine("Your String is exist");
}
I would prefer to use Linq to check that S in this regard is exist, no matter how the order is in the list, but it contains both (#30) and (#20) [at least] together in that list XAll.
I am using
var c = item2.Intersect(item1);
if (c.Count() == item1.Length)
{
return true;
}
You should represent your data in a more meaningful way. Don't rely on strings.
For example I would suggest creating a type to represent a set of these numbers and write some code to populate it.
But there are already set types such as HashSet which is possibly a good match with built in functions for testing for sub sets.
This should get you started:
var input = "#20#30#40";
var hashSetOfNumbers = new HashSet<int>(input
.Split(new []{'#'}, StringSplitOptions.RemoveEmptyEntries)
.Select(s=>int.Parse(s)));
This works for me:
Func<string, string[]> split =
x => x.Split(new [] { '#' }, StringSplitOptions.RemoveEmptyEntries);
if (XAll.Any(x => split(x).Intersect(split(S)).Count() == split(S).Count()))
{
Console.WriteLine("Your String is exist");
}
Now, depending on you you want to handle duplicates, this might even be a better solution:
Func<string, HashSet<string>> split =
x => new HashSet<string>(x.Split(
new [] { '#' },
StringSplitOptions.RemoveEmptyEntries));
if (XAll.Any(x => split(S).IsSubsetOf(split(x))))
{
Console.WriteLine("Your String is exist");
}
This second approach uses pure set theory so it strips duplicates.
Apologies if the answer to this is obvious, I'm fairly new to C# and OOP. I've stepped though my code and spent quite some time on Google but I can't find the answer to my question (quite possibly because I am using the wrong search terms!).
I have the following class that creates a static List<List<string>> and has a method to add items to that list:
public static class WordList
{
static List<List<string>> _WordList; // Static List instance
static WordList()
{
//
// Allocate the list.
//
_WordList = new List<List<string>>();
}
public static void Record(List<string> Words)
{
//
// Record this value in the list.
//
_WordList.Add(Words);
}
}
Else where I create a List<string> which I pass into the Record() method to be added to _WordList. The problem is when I add items to WordList it gives every item in that list the same value. e.g.:
1st item added contains "Foo" and "bar"
2nd item added contains "Not","Foo" and "bar"
So instead of a list that looks like:
1: "Foo","bar"
2: "Not","Foo","bar"
I end up with:
1: "Not","Foo","bar"
2: "Not","Foo","bar"
I haven't used a List<string[]> instead of a List<List<string>> because the way I am getting the List<string> to add is by reading a text file line by line with a delimiter saying when I should add the List<string> and clear it so I can start again. Therefore I don't know how long an array I need to declare.
Hope this makes some kind of sense! If you need anymore of the code posting to help let me know.
Thanks, in advance.
EDIT
Here is the code for the creation of the List<string> that is passed to the Record() method. I think I see what people are saying about not creating a new instance of the List<string> but I'm not sure how to remedy this in regards to my code. I will have a think about it and post an answer if I come up with one!
public static void LoadWordList(string path)
{
string line;
List<string> WordsToAdd = new List<string>();
StreamReader file = new System.IO.StreamReader(path);
while ((line = file.ReadLine()) != null)
{
if (line.Substring(0, 1) == "$")
{
WordList.Record(WordsToAdd);
WordsToAdd.Clear();
WordsToAdd.Add(line.Replace("$", ""));
}
else
{
WordsToAdd.Add(line.Replace("_"," "));
}
}
file.Close();
}
Instead of
WordList.Record(WordsToAdd);
WordsToAdd.Clear();
WordsToAdd.Add(line.Replace("$", ""));
do
WordList.Record(WordsToAdd);
WordsToAdd = new List<string>();
WordsToAdd.Add(line.Replace("$", ""));
All that your Record method is doing is adding a reference to the List<string> you've passed to it. You then clear that same list, and start adding different strings to it.
Maybe something like:
public static void Record(IEnumerable<string> Words)
{
_WordList.Add(Words.ToList());
}
Which will force a copy to occur; also, by accepting IEnumerable<string>, it puts less restrictions on the code that calls it.
Can you post the code that adds the list - I bet you are doing something like
create a list l
add it
modify l
add it
This result in a single object (because you created it only once) with multiple references to it, namely from the first value in _WordList, from the second value in _WordList, from l.
So the right way to do it is:
create list l
add it
create NEW list l
add it
Or in code:
List<string> l = new string[] { "Foo", "bar" }.ToList();
WordList.Record(l);
l = new string[] { "Not", "Foo", "bar" }.ToList();
WordList.Record(l);
You haven't shown how you are adding items to the list. Here's an example which works as expected:
using System;
using System.Collections.Generic;
using System.Linq;
public static class WordList
{
static List<List<string>> _WordList; // Static List instance
static WordList()
{
_WordList = new List<List<string>>();
}
public static void Record(List<string> Words)
{
_WordList.Add(Words);
}
public static void Print()
{
foreach (var item in _WordList)
{
Console.WriteLine("-----");
Console.WriteLine(string.Join(",", item.ToArray()));
}
}
}
class Program
{
static void Main()
{
WordList.Record(new[] { "Foo", "bar" }.ToList());
WordList.Record(new[] { "Not", "Foo", "bar" }.ToList());
WordList.Print();
}
}
I have a string[] which contains value {"data1","data2","data3"}.
and i have a GenericList which contains
data2
data4
two records
i want to get the common datas which is avail in string[] and the genericList
Have you tried something like
string[] s = {"data1", "data2", "data3"};
List<string> list = new List<string> { "data2", "data3" };
var commonList = list.Intersect(s);
Have a look at Enumerable.Intersect Method (IEnumerable, IEnumerable)
Assuming it's a List<string> and you're using .NET 3.5 or higher, you can use the Intersect method from LINQ to Objects:
var intersection = stringArray.Intersect(stringList);
Note that this will return a lazily-evaluated IEnumerable<string>. If you need it in an array or a list, call the relevant method:
var intersectionArray = stringArray.Intersect(stringList).ToArray();
// or
var intersectionList = stringArray.Intersect(stringList).ToList();
Also note that this is a set operation - so the result will not contain any duplicates, even if there is duplication of a particular element in both the original collections.
Take a look at the Intersect extension method here
string[] c1 = { "data1", "data2", "data3" };
string[] c2 = { "data2", "data4" };
IEnumerable<string> both = c1.Intersect(c2);
foreach (string s in both) Console.WriteLine(s);
Will print data2.