What will be the linq query for below code? - c#

class Program
{
public static bool Like(string toSearch,string toFind)
{
if (toSearch.Contains(toFind))
return true;
else
return false;
}
static void Main(string[] args)
{
List<string> str = new List<string>();
List<string> strNew = new List<string>();
str.Add("abdecacd");
str.Add("facdgh");
str.Add("iabcacdjk");
str.Add("lmn");
str.Add("opqe");
str.Add("acbd");
str.Add("efgh");
string strToSearch= "acd,abc,abcacd,al";
string[] desc = strToSearch.Split(',');
for(int i = 0; i < str.Count; i++)
{
for(int j = 0; j < desc.Length; j++)
{
if(Like(str[i].ToString(),desc[j].ToString()))
{
strNew.Add(str[i].ToString());
break;
}
}
}
if(strNew != null)
{
foreach(string strPrint in strNew)
{
Console.WriteLine(strPrint);
}
}
}
}
How to write a linq query for above code,in this strToSearch variable value will be dynamic,user will enter comma separated values,user may enter as many comma separated values as user wants,I want to write a linq query which will find all the values in List which will contain the value entered by user.
Reason I need linq query,because linq is used in my application. Kindly help me out on this.

The LINQ expression is:
List<string> strNew = str.Where(x => desc.Any(y => x.Contains(y))).ToList();
that can even be simplified (simplified for the .NET runtime, not for the programmer) to:
List<string> strNew = str.Where(x => desc.Any(x.Contains)).ToList();
by removing an intermediate lambda function.
In general there is no "speed" difference between what you wrote and what I wrote. Both expressions are O(m*n), with m = str.Length and n = desc.Length, so O(x^2). You aren't doing an exact search, so you can't use the usual trick of creating an HashSet<string> (or doing str.Intersect(desc).ToList() that internally does the same thing).

Related

HackerRank Sparse Arrays Challenge C#

There is a collection of input strings and a collection of query strings. For each query string, determine how many times it occurs in the list of input strings. Return an array of the results.
Function Description
The function matchingStrings must return an array of integers representing the frequency of occurrence of each query string in strings.
matchingStrings has the following parameters:
string strings[n] - an array of strings to search
string queries[q] - an array of query strings
Returns
int[q]: an array of results for each query
Solution
List<string> strings = new List<string> { "4", "aba", "baba", "aba", "xzxb" };
List<string> queries = new List<string> { "3", "aba", "xzxb", "ab" };
List<int> outputList = Result.matchingStrings(strings, queries);
for (int i = 0; i < outputList.Count; i++)
{
Console.WriteLine(outputList[i]);
}
public class Result
{
public static List<int> matchingStrings(List<string> strings, List<string> queries)
{
int inputCount = 0;
Int32.TryParse(strings[0], out inputCount);
string[] input = strings.GetRange(1, strings.Count - 1).ToArray();
var stringsMap = new Dictionary<string, int>();
for (int i = 0; i < inputCount; i++)
{
if (stringsMap.ContainsKey(input[i]))
{
stringsMap[input[i]]++;
}
else
{
stringsMap.Add(input[i], 1);
}
}
int queryCount = 0;
Int32.TryParse(queries[0], out queryCount);
string[] queryStrings = queries.GetRange(1, queries.Count - 1).ToArray();
int[] output = new int[queryCount];
for (int i = 0; i < queryCount; i++)
{
if (stringsMap.ContainsKey(queryStrings[i]))
{
output[i] = stringsMap[queryStrings[i]];
}
}
List<int> outputList = output.ToList();
return outputList;
}
}
The code works fine for the given sample input in VS code. However, when it is inserted into the HackerRank online IDE, it returns no output. I do not understand what the problem could be.
This is my 100% solution in C#:
List<int> res = new List<int>();
int count=0;
for(int i=0; i<queries.Count; i++) {
count=0;
foreach(string s in strings) {
if(queries[i] == s) {
count++;
}
}
res.Add(count);
}
return res;
}
this is my solution in python
def matchingStrings(strings, queries):
hash_map=dict()
results=[]
for str in strings:
if str in hash_map:
hash_map[str]+=1
else:
hash_map[str]=1
for q in queries:
if q in hash_map:
results.append(hash_map[q])
else:
results.append(0)
return results
public static List<int> matchingStrings(List<string> strings, List<string> queries)
{
int count = 0;
List<int> countOfOccurences = new List<int>();
foreach(var query in queries){
count = strings.Where(x => x == query).Count();
countOfOccurences.Add(count);
}
return countOfOccurences;
}

Algorithm for shortest list of words

The issue is as follows: the user provides a StartWord and EndWord string of X letters together with a list of strings that are also of length X (lets make it 4 but probably more)
static void Main(string[] args)
{
string StartWord = "Spot";
string EndWord = "Spin";
List<string> providedList = new List<string>
{
"Spin", "Spit", "Spat", "Spot", "Span"
};
List<string> result = MyFunc(StartWord, EndWord, providedList);
}
public List<string> MyFunc(string startWord, string endWord, List<string> input)
{
???
}
From the provided parameters I need to display to the user a result that comprises of the SHORTEST list of 4 letter words, starting with StartWord and ending with EndWord with a number of intermediate words that are to be found in the list, where each word differs from the previous word by PRECISELY one letter.
For example the above code should return a list of strings containing these elements:
Spot(as FirstWord),
Spit(only one letter is different from previous word),
Spin (as EndWord)
A bad exapmle would be: Spot, Spat, Span, Spin (as it takes 3 changes compared to the above 2)
I have been looking at some matching algorithms and recursion, but I am not able to figure out how to go about this.
Thank you for any kind of help in advance.
Create a graph where the vertices are words, and an edge connects any two words that differ by one letter.
Do a breadth-first search, starting at the StartWord, looking for the shortest path to the EndWord.
Here is sample code for this solution in a different language (Python). That may give you an even better pointer. :-)
def shortestWordPath (startWord, endWord, words):
graph = {}
for word in words:
graph[word] = {"connected": []}
for word in words:
for otherWord in words:
if 1 == wordDistance(word, otherWord):
graph[word]['connected'].append(otherWord)
todo = [(startWord,0)]
while len(todo):
(thisWord, fromWord) = todo.pop(0)
if thisWord == endWord:
answer = [thisWord, fromWord]
while graph[ answer[-1] ]["from"] != 0:
answer.append(graph[ answer[-1] ]["from"])
answer.reverse()
return answer
elif "from" in graph[thisWord]:
pass # We have already processed this.
else:
graph[thisWord]["from"] = fromWord
for nextWord in graph[thisWord]["connected"]:
todo.append([nextWord, thisWord])
return None
def wordDistance (word1, word2):
return len(differentPositions(word1, word2))
def differentPositions(word1, word2):
answer = []
for i in range(0, min(len(word1), len(word2))):
if word1[i] != word2[i]:
answer.append(i)
for i in range(min(len(word1), len(word2)),
max(len(word1), len(word2))):
answer.append(i)
return answer
print shortestWordPath("Spot", "Spin",
["Spin", "Spit", "Spat", "Spot", "Span"])
This is what I ended up using(please feel free to comment on the up and down side of it):
private List<List<string>> allWordSteps;
private string[] allWords;
public List<string> WordLadder(string wordStart, string wordEnd, string[] allWordsInput)
{
var wordLadder = new List<string>() { wordStart };
this.allWordSteps = new List<List<string>>() { wordLadder };
allWords = allWordsInput;
do
{
wordLadder = this.IterateWordSteps(wordEnd);
}
while (wordLadder.Count() == 0);
return wordLadder;
}
private List<string> IterateWordSteps(string wordEnd)
{
List<List<string>> allWordStepsCopy = this.allWordSteps.ToList();
this.allWordSteps.Clear();
foreach (var wordSteps in allWordStepsCopy)
{
var adjacent = this.allWords.Where(
x => this.IsOneLetterDifferent(x, wordSteps.Last()) &&
!wordSteps.Contains(x));
if (adjacent.Contains(wordEnd))
{
wordSteps.Add(wordEnd);
return wordSteps;
}
foreach (var word in adjacent)
{
List<string> newWordStep = wordSteps.ToList();
newWordStep.Add(word);
this.allWordSteps.Add(newWordStep);
}
}
return new List<string>();
}
private bool IsOneLetterDifferent(string first, string second)
{
int differences = 0;
if (first.Length == second.Length)
{
for (int i = 0; i < first.Length; i++)
{
if (first[i] != second[i])
{
differences++;
}
}
}
return differences == 1;
}

List sorting by multiple parameters

I have a .csv with the following headers and an example line from the file.
AgentID,Profile,Avatar,In_Time,Out_Time,In_Location,Out_Location,Target_Speed(m/s),Distance_Traveled(m),Congested_Duration(s),Total_Duration(s),LOS_A_Duration(s),LOS_B_Duration(s),LOS_C_Duration(s),LOS_D_Duration(s),LOS_E_Duration(s),LOS_F_Duration(s)
2177,DefaultProfile,DarkGreen_LowPoly,08:00:00,08:00:53,East12SubwayportalActor,EWConcourseportalActor,1.39653,60.2243,5.4,52.8,26.4,23,3.4,0,0,0
I need to sort this .csv by the 4th column (In_time) by increasing time ( 08:00:00, 08:00:01) and the 6th (In_Location) by alphabetical direction (e.g. East, North, etc).
So far my code looks like this:
List<string> list = new List<string>();
using (StreamReader reader = new StreamReader("JourneyTimes.csv"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
line.Split(',');
list.Add(line);
}
I read in the .csv and split it using a comma (there are no other commas so this is not a concern). I then add each line to a list. My issue is how do I sort the list on two parameters and by the headers of the .csv.
I have been looking all day at this, I am relatively new to programming, this is my first program so I apologize for my lack of knowledge.
You can use LINQ OrderBy/ThenBy:
e.g.
listOfObjects.OrderBy (c => c.LastName).ThenBy (c => c.FirstName)
But first off, you should map your CSV line to some object.
To map CSV line to object you can predefine some type or create it dynamically
from line in File.ReadLines(fileName).Skip(1) //header
let columns = line.Split(',') //really basic CSV parsing, consider removing empty entries and supporting quotes
select new
{
AgentID = columns[0],
Profile = int.Parse(columns[1]),
Avatar = float.Parse(columns[2])
//other properties
}
And be aware that like many other LINQ methods, these two use deferred execution
You are dealing with two distinct problems.
First, ordering two columns in C# can be achieved with OrderBy, ThenBy
public class SpreadsheetExample
{
public DateTime InTime { get; set; }
public string InLocation { get; set; }
public SpreadsheetExample(DateTime inTime, string inLocation)
{
InTime = inTime;
InLocation = inLocation;
}
public static List<SpreadsheetExample> LoadMockData()
{
int maxMock = 10;
Random random = new Random();
var result = new List<SpreadsheetExample>();
for (int mockCount = 0; mockCount < maxMock; mockCount++)
{
var genNumber = random.Next(1, maxMock);
var genDate = DateTime.Now.AddDays(genNumber);
result.Add(new SpreadsheetExample(genDate, "Location" + mockCount));
}
return result;
}
}
internal class Class1
{
private static void Main()
{
var mockData = SpreadsheetExample.LoadMockData();
var orderedResult = mockData.OrderBy(m => m.InTime).ThenBy(m => m.InLocation);//Order, ThenBy can be used to perform ordering of two columns
foreach (var item in orderedResult)
{
Console.WriteLine("{0} : {1}", item.InTime, item.InLocation);
}
}
}
Now you can tackle the second issue of moving data into a class from Excel. VSTO is what you are looking for. There are lots of examples online. Follow the example I posted above. Replace your custom class in place of SpreadSheetExample.
You may use a DataTable:
var lines = File.ReadAllLines("test.csv");
DataTable dt = new DataTable();
var columNames = lines[0].Split(new char[] { ',' });
for (int i = 0; i < columNames.Length; i++)
{
dt.Columns.Add(columNames[i]);
}
for (int i = 1; i < lines.Length; i++)
{
dt.Rows.Add(lines[i].Split(new char[] { ',' }));
}
var rows = dt.Rows.Cast<DataRow>();
var result = rows.OrderBy(i => i["In_time"])
.ThenBy(i => i["In_Location"]);
// sum
var sum = rows.Sum(i => Int32.Parse(i["AgentID"].ToString()));

Getting a variable from a list of objects

How would you get a variable from each object in a list?
I've got this so far:
void SortList()
{
int j = modules.Count;
string[] titles = new string[j];
for (int i = 0; i > modules.Count; i++)
{
titles[i] =
}
}
And I'm trying to get the variable "code" from each object in modules.
thanks.
Implying modules is a list or an array,
void SortList()
{
int j = modules.Count;
string[] titles = new string[j];
foreach (String title in modules)
{
titles[i] = title.code
}
}
As stated by Cuong Le, you could also use Linq to get a shorter version (Depending of which .Net version you are on).
titles = modules.Select(x => x.code).ToArray();
You can use LINQ with simple code with Select method:
titles = modules.Select(x => x.code).ToArray();

Permutations using same letters

I am current working on a project where I need to generate all possible permutations from a given set of characters. I am currently using this code:
public static IEnumerable<string> AllPermutations(this IEnumerable<char> s)
{
return s.SelectMany(x =>
{
var index = Array.IndexOf(s.ToArray(), x);
return s.Where((y, i) => i != index).AllPermutations().Select(y => new string(new[] { x }.Concat(y).ToArray())).Union(new[] { new string(new[] { x }) });
}).Distinct();
}
From this answer.
The problem I have is that it won't generate permuations that use the same letter more than once.
For example if I used abcde as the input I need it to generate combinations like aaaaa and dcc etc.
I'm not experienced enough with LINQ to understand where the code is stopping duplicate letters. Any help is greatly appreciated.
This might work, but I'm sure it could be done more efficiently (taking the counting prompt from PeskyGnat):
static IEnumerable<string> GetVariations(string s)
{
int[] indexes = new int[s.Length];
StringBuilder sb = new StringBuilder();
while (IncrementIndexes(indexes, s.Length))
{
sb.Clear();
for (int i = 0; i < indexes.Length; i++)
{
if (indexes[i] != 0)
{
sb.Append(s[indexes[i]-1]);
}
}
yield return sb.ToString();
}
}
static bool IncrementIndexes(int[] indexes, int limit)
{
for (int i = 0; i < indexes.Length; i++)
{
indexes[i]++;
if (indexes[i] > limit)
{
indexes[i] = 1;
}
else
{
return true;
}
}
return false;
}
Edit: Changed to use yield return as per Rawlings suggestion. Much better memory usage if you don't need to keep all the results and you can start using the results before they've all been generated.
I'm amazed this works. It basically goes "make a list of strings from the characters. Then to each string taken from the list, add each character again, and add the resulting strings to the list. Repeat until you've got the right length."
public static IEnumerable<string> BuildStrings(this IEnumerable<char> alphabet)
{
var strings = alphabet.Select(c => c.ToString());
for (int i = 1; i < alphabet.Count(); i++)
{
strings = strings.Union(strings.SelectMany(s => alphabet.Select(c => s + c.ToString())));
}
return strings;
}
A funny one using only recursive lambdas via a fixpoint operator (thx #Rawling for the SelectMany)
// Fix point operator
public static Func<T, TResult> Fix<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> f)
{
return t => f(Fix<T, TResult>(f))(t);
}
And then
var chars = new[] {'a','b','c','d','e'}.Select(c=>c.ToString()) ;
var result = Fix<int,IEnumerable<string>>(
f =>
x =>
x == 1
? chars
: chars.Union(f(x - 1).SelectMany(s => chars.Select(c => s + c))))(chars.Count());

Categories

Resources