I have a file with allot of sentences. I need to make a dictionary with the words from that file. Until now I've separated the words and sort them using Split() and Sort() methods. My problem is to make a list without duplicate words. How can I do that?
static int n = 0;
public static string[] NoDuplicate(string[] array)
{
int i;
string[] res = (string[])array.Clone();
for (i = 0; i < array.Length-1; i++)
{
if (array[i + 1] != array[i])
res[n++] = (string)array[i];
}
return res;
}
how can I do it more neat?
I don't like that method because is
initialized using Clone() and the length is too big.
You can also use HashSet beside the .Distinct() feature of LINQ:
HashSet:
This is an optimized set collection. It helps eliminates
duplicate strings or elements in an array. It is a set that hashes its
contents.
public static string[] NoDuplicate(string[] array)
{
string[] result = new HashSet<string>(array).ToArray();
return result;
}
If you want to eliminate the duplicate with case-insensitive, you can pass an IEqualityComparer argument like this:
Using HashSet:
public static string[] NoDuplicate(string[] array)
{
string[] result = new HashSet<string>(array, StringComparer.OrdinalIgnoreCase)
.ToArray();
return result;
}
Using LINQ's Distict feature:
public static string[] NoDuplicate(string[] array)
{
string[] result = array.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
return result;
}
Try this:
private static string[] NoDuplicate(string[] inputArray)
{
var result = inputArray.Distinct().ToArray();
return result;
}
Instead of dictionary create a trie of words.
At each level keep a count of sameWord if it repeats. This way you can avoid using too much space and it will be faster to search any word O(log(n))
where n is number of distinct words
public class WordList {
private int sameWord = 0;
String name = "";
WordList [] child = new WordList[26];
public void add( String s, WordList c, int index )
{
sameWord++;
if(index > 0)
{
name += ""+s.charAt(index-1);
}
if(index == s.length())
{
return;
}
if(c.child[s.charAt(index)-'a'] ==null)
{
c.child[s.charAt(index)-'a'] = new WordList();
}
add(s,c.child[s.charAt(index)-'a'],index+1);
}
public static WordList findChar(char c)
{
return child[(int)(c-'a')];
}
}
You can try below solution:
private static string[] NoDuplicate(string[] inputArray)
{
List<string> stringList = new List<string>();
foreach (string s in inputArray)
{
if (!stringList.Contains(s))
{
stringList.Add(s);
}
}
return stringList.ToArray();
}
Related
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;
}
I have two string lists, I need to do a comparison and validate at least if one position is the same.
Can someone help me?
List<string> listA = new List<string>();
listA.Add("b");
listA.Add("c");
listA.Add("a");
List<string> listB = new List<string>();
listB.Add("h");
listB.Add("b");
listB.Add("d");
Expected output:
b = h false
b = b true (break)
b = d false
You should use LINQ:
if (listA.Intersect(listB).Any())
{
//do smth;
}
Given that the lists are the same size, some function/method like:
for (int index = 0; index < listA.Count; index++) {
if (listA[index] == listB[index]) {
return true;
}
}
Should work.
If the lists arn't the same size, you can then do something like.
int smallListCount = listA.Count;
if (smallListCount > listB.Count) {
smallListCount = listB.Count;
}
for (int index = 0; index < smallListCount; index++) { /*... codeblah*/ }
That'll make sure it'll only loop for as many elements as there are able to be compared in the smallest list.
Erp! If you don't care about the order of the indexes then...
You'll need some function/method that can take any input, then iterates over listB to see if there is a match, returning true... if well... it finds a match.
You'd then want to feed in the values of listA, and store the result for each element.
private bool CheckListForItem(List<string> listToCheck, string itemToCheckFor) {
foreach(string item in listToCheck) {
if (item == itemToCheckFor) {
return true;
}
}
return false;
}
which can then be used like:
bool[] results = new results[listA.Count];
for(int index = 0; index < listA.Count; index++) {
results[index] = CheckListForItem(listB, listA[index]);
}
to obtain results for each individual item.
Note that this will have a complexity of O(n), I'd assume LINQ is faster. But hey, this exposes a potential implementation! Kinda.
Try to use Except LINQ extension method, which takes items only from the first list, that are not present in the second
List<string> resultList = listA.Except(listB).ToList();
Here is something that does exactly what you want and doesnt use Linq if you arent familiar with it.
We extend a List class and add CompareLists method to it and then called it to see if any value is the same in both lists.
public static class Extensions
{
public static bool CompareLists(this List<string> listA, List<string> listB)
{
foreach (string s in listA)
{
foreach (string s1 in listB)
{
if (s.Equals(s1))
{
return true;
}
}
}
return false;
}
}
and then use it like
var result = listA.CompareLists(listB);
with a little tweaking you can make it return a list of objects that are or arent equal.
public static class Extensions
{
public static List<string> CompareLists(this List<string> listA, List<string> listB)
{
List<string> results = new List<string>();
foreach (string s in listA)
{
foreach (string s1 in listB)
{
if (s.Equals(s1))
{
results.Add(s);
}
}
}
return results;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, string> aStr = new Dictionary<string, string>();
aStr.Add("FONT_BOLD_4DSTR_CORRECT", "VALUE");
ICollection<string> strCol = aStr.Keys;
if (strCol.Contains("FONT_BOLD_4DSTR"))
{
Console.WriteLine("hurrah string found");
}
int count = 0;
foreach(string a in strCol)
{
if (a.Contains("FONT_BOLD_4DSTR"))
{
count++;
}
}
if(aStr.Keys.ToList().Contains("FONT_BOLD_4DSTR"))
{
Console.WriteLine("list found the bold data");
}
Console.WriteLine("the number of string count is {0}", count);
Console.Read();
}
}
Need to find the substring in dictionary keys. If i do string.contains, able to find the substring.
If keys are stored in collection or converted to list, not able to find the substring. Is there any way to find substring using lists or collection contains.
Use LinQ:
ICollection<string> strCol = aStr.Keys;
if (strCol.Any( a => a.Contains("FONT_BOLD_4DSTR") ))
{
Console.WriteLine("hurrah string found");
}
You could use a little LINQ:
bool hasKey = aStr.Keys.Any(k => k.Contains("FONT_BOLD_4DSTR"));
if (hasKey) {
// found the bold data
}
If you need the count too, rearrange your logic a bit:
int matchCount = aStr.Keys.Count(k => k.Contains("FONT_BOLD_4DSTR"));
bool hasKey = matchCount > 0;
I have the following code below that reads in text file and searches it for integers. I am using 'int.TryParse' to do this but it is not storing the integer values in the lists after it has run, just wondering if you could tell me what is wrong with this code. Thanks.
namespace AccessErrorFile
{
class Program
{
static void Main(string[] args)
{
List<int> plans = new List<int>();
List<int> events = new List<int>();
using (var reader = new StreamReader(#"D:\Temp\AccessEmail.txt"))
try
{
string line;
while ((line = reader.ReadLine()) != null)
{
//split the line
string[] parts = line.Split(new[] { "Event" }, StringSplitOptions.None);
//get valid integers
plans.Add(GetInt(parts[0].Split(' ', '\'')));
events.Add(GetInt(parts[1].Split(' ', '\'')));
}
}
catch (System.Exception ex)
{
Console.WriteLine("Error" + ex.Message);
}
//print the elements in the lists
foreach (int x in plans)
{
Console.WriteLine(x);
}
foreach (int y in events)
{
Console.WriteLine(y);
}
//print the number of elements in the lists
Console.WriteLine(plans.Count);
Console.WriteLine(events.Count);
Console.ReadLine();
}
public static int GetInt(string[] a)
{
int i = 0;
foreach (string s in a)
int.TryParse(s, out i);
return i;
}
}
}
your problem is
public static int GetInt(string[] a)
{
int i = 0;
foreach (string s in a) //HERE
int.TryParse(s, out i); //AND HERE
return i;
}
you are parsing in the loop, so the return i statement returns basically the last s of iteration, which, most probably is not a number, so i=0.
If you want to add all numbers from the string to array of ints, you can do something like:
IEnumerable<int> GetNumbersFromList(string[] s) {
foreach(var str in s) {
int val;
if(int.TryParse(str, out val))
yield return val;
}
}
and after
plans.AddRange(GetNumbersFromList(parts));
Just a basic idea, naturally, you have to fit it to your needs.
I have a text box field inputs 123,145,125 I to separate this field into an array of integers. And validate this field true or false if everything is parsed right.
CODE:
private bool chkID(out int[] val)
{
char[] delimiters = new char[] { ',' };
string[] strSplit = iconeID.Text.Split(delimiters);
int[] intArr = null;
foreach (string s in strSplit) //splits the new parsed characters
{
int tmp;
tmp = 0;
if (Int32.TryParse(s, out tmp))
{
if (intArr == null)
{
intArr = new int[1];
}
else
{
Array.Resize(ref intArr, intArr.Length + 1);
}
intArr[intArr.Length - 1] = tmp;
}
if (Int32.TryParse(iconeID.Text, out tmp))
{
iconeID.BorderColor = Color.Empty;
iconeID.BorderWidth = Unit.Empty;
tmp = int.Parse(iconeID.Text);
val = new int[1];
val[0] = tmp;
return true;
}
}
val = null;
ID.BorderColor = Color.Red;
ID.BorderWidth = 2;
return false;
}
//new Code:
private bool chkID(out int[] val) //bool satus for checkID function
{
string[] split = srtID.Text.Split(new char[1] {','});
List numbers = new List();
int parsed;
bool isOk = true;
foreach( string n in split){
if(Int32.TryParse( n , out parsed))
numbers.Add(parsed);
else
isOk = false;
}
if (isOk){
strID.BorderColor=Color.Empty;
strID.BorderWidth=Unit.Empty;
return true;
} else{
strID.BorderColor=Color.Red;
strID.BorderWidth=2;
return false;
}
return numbers.ToArray();
}
The given function seems to do too much. Here's one that answers the question implied by your title:
//int[] x = SplitStringIntoInts("1,2,3, 4, 5");
static int[] SplitStringIntoInts(string list)
{
string[] split = list.Split(new char[1] { ',' });
List<int> numbers = new List<int>();
int parsed;
foreach (string n in split)
{
if (int.TryParse(n, out parsed))
numbers.Add(parsed);
}
return numbers.ToArray();
}
EDIT (based on your comment on the question)
You've defined the three things this function needs to do. Now you just need to create methods for each. Below are my guesses for how you could implement them.
int[] ValidateIDs(int[] allIDs)
{
List<int> validIDs = new List<int>(allIDs);
//remove invalid IDs
return validIDs.ToArray();
}
void DownloadXmlData(int[] ids)
{
...
}
Now you just execute your new functions:
void CheckIconeID(string ids)
{
int[] allIDs = SplitStringIntoInts(ids);
int[] validIDs = ValidateIDs(allIDs);
DownloadXmlData(validIDs);
}
I really wanted to comment on #Austin Salonen's answer, but it didn't fit. It is a great answer for the question asked, but i wanted to expand the discussion a bit more generally on csv/int conversion part.
It's small point, not worth much debate but I would consider swapping the foreach loop for a plain for loop. You'll likely end up with simpler IL (read faster). See (http://www.codeproject.com/KB/cs/foreach.aspx, http://msdn.microsoft.com/en-us/library/ms973839.aspx [Use For Loops for String Iteration—version 1]).
I would create two methods -- one that is safe and uses TryParse and only adds the "good" values, another that is not as safe, but faster.
Proposed "safe" function (with overload in case you don't want to know the bad values)...
public static int[] SplitAsIntSafe (this string csvString) {
List<string> badVals;
return SplitAsIntSafe(csvString, ',', out badVals);
}
public static int[] SplitAsIntSafe (this string delimitedString, char splitChar, out List<string> badVals) {
int parsed;
string[] split = delimitedString.Split(new char[1] { ',' });
List<int> numbers = new List<int>();
badVals = new List<string>();
for (var i = 0; i < split.Length; i++) {
if (int.TryParse(split[i], out parsed)) {
numbers.Add(parsed);
} else {
badVals.Add(split[i]);
}
}
return numbers.ToArray();
}
Proposed "fast" function ....
public static int[] SplitAsIntFast (this string delimitedString, char splitChar) {
string[] strArray = delimitedString.Split(splitChar);
int[] intArray = new int[strArray.Length];
if(delimitedString == null) {
return new int[0];
}
for (var i = 0; i < strArray.Length; i++) {
intArray[i] = int.Parse(strArray[i]);
}
return intArray;
}
Anyway, hope this helps someone.
It might be worth your while to check out this FileHelper and also CSV Reader
Hope they will help you...
Take care,
Tom
There is a good free library for parsing CSV files: FileHelpers
using FileHelpers;
// First declare the record class
[Delimitedrecord(";")]
public class SampleType
{
public string Field1;
public int Field2;
}
public void ReadExample()
{
FileHelperEngine engine = new FileHelperEngine(typeof(SampleType));
SampleType[] records;
records = (SampleType[]) engine.ReadFile("source.txt");
// Now "records" array contains all the records in the
// sourcefile and can be acceded like this:
int sum = records[0].Field2 + records[1].Field2;
}
public bool ParseAndCheck(string source,
out IList<int> goodItems, out IList<string> badItems)
{
goodItems = new List<int>();
badItems = new List<string>();
foreach (string item in source.Split(','))
{
int temp;
if (int.TryParse(item, out temp))
goodItems.Add(temp);
else
badItems.Add(item);
}
return (badItems.Count < 1);
}
In .NET 2.0 you could write
string test = "123,14.5,125,151,1.55,477,777,888";
bool isParsingOk = true;
int[] results = Array.ConvertAll<string,int>(test.Split(','),
new Converter<string,int>(
delegate(string num)
{
int r;
isParsingOk &= int.TryParse(num, out r);
return r;
}));
This is simple and I think works pretty well. It only return valid numbers:
static int[] SplitStringIntoInts(string list)
{
int dummy;
return (from x in list.Split(',')
where int.TryParse(x.ToString(), out dummy)
select int.Parse(x.ToString())).ToArray();
}