C# Replace All Vowels in Generic List - c#

How do I replace all vowels in list with a space? Following code does not seem to be working.
List<string> Instruments = new List<string>();
Instruments.Add("cello");
Instruments.Add("guitar");
Instruments.Add("violin");
Instruments.Add("double bass");
string vowels = "a e i o u y";
Instruments.ForEach(w=>vowels = vowels.Replace(w,""));
Expected Result:
cll
gtr
vln

Try this
var vowels = new List<char> {'a','e','i','o','u','y'};
var result = new List<string>();
Instruments.ForEach(w => result.Add(new string(w.Select(x => vowels.Any(y => y == x) ? ' ' : x).ToArray())));

You should use .Select if need to changes values in Collection:
List<string> Instruments = new List<string>();
Instruments.Add("cello");
Instruments.Add("guitar");
Instruments.Add("violin");
Instruments.Add("double bass");
var regex = new Regex("^a|e|i|o|u", RegexOptions.IgnoreCase);
var withoutVowels = from instr in Instruments
select regex.Replace(instr, string.Empty);
foreach (var item in withoutVowels)
{
Console.WriteLine(item);
}

A little quick and dirty but this works for me.
List<string> Instruments = new List<string>();
var newList = new List<String>();
Instruments.Add("cello");
Instruments.Add("guitar");
Instruments.Add("violin");
Instruments.Add("double bass");
List<string> vowels = new List<string> { "a", "e", "i", "o", "u", "y" };
Instruments.ForEach(w =>
{
var temp = w;
vowels.ForEach(v =>
{
temp = temp.Replace(v, "");
});
newList.Add(temp);
});
newList.ForEach(w => Console.WriteLine(w));

You could try the same with with Regex:
public void ReplaceAllVowels()
{
List<string> Instruments = new List<string>();
Instruments.Add("cello");
Instruments.Add("guitar");
Instruments.Add("violin");
Instruments.Add("double bass");
var pattern = new Regex("[aeiouy]");
var lst = Instruments.Select(i => pattern.Replace(i, "")).ToList();
foreach (var item in lst)
{
Console.WriteLine(item);
}
}

Instruments has a collection of string, or words, in it. Your .ForEach iterates through that collection where each instance is w, but you're not affecting those instances with your usage of .Replace here, you're using them in an operation to affect the string vowels.
see String.Replace MSN Documentation.
As such, you need to also iterate through your vowels string, and use the charinstance of vowels: w.Replace(v, " "), where w is your word instance in Instruments, and v is your vowel instance in vowels:
So, it should be Instruments.ForEach(w => foreach (vowelChar in vowels.split(" ")) { w.Replace(vowelChar, " "); });
Note: #mjwills pointed out the other issue with this operation in comments. the assignment to w won't persist here. so, you'll need to create new List<string> in some fashion to persist it (either declare it before hand and add to it in iteration, or use Linq .ToList<T> Extension of IEnumerable<T>.
However, that is inefficient since you're essentially creating a char[] from vowels string using .Split on each iteration of Instruments.
Instead, you should defined your vowels as a char[] to avoid the necessity of that operation: var vowels = new char[] {'a','e','i','o','u', 'y'};
List<string> Instruments = new List<string>();
Instruments.Add("cello");
Instruments.Add("guitar");
Instruments.Add("violin");
Instruments.Add("double bass");
char[] vowels = new char[] {'a','e','i','o','u','y'};
Instruments.ForEach(w => {
foreach (char v in vowels) {
w = w.Replace(v, ' ');
}
});
EDIT: assigning to w instances of Instruments in the iteration don't persist, so you would need to create a new instance of List<string> for your results.
List<string> results = new List<string>();
Instruments.ForEach(w => {
foreach (char v in vowels) {
results.Add(w.Replace(v, ' '));
}
});
results.ForEach(w => Console.WriteLine(w));

This works nicely for me:
List<string> Instruments = new List<string>();
Instruments.Add("cello");
Instruments.Add("guitar");
Instruments.Add("violin");
Instruments.Add("double bass");
string vowels = "aeiouy";
var results = vowels.Aggregate(Instruments,
(i, v) => i.Select(x => x.Replace(v.ToString(), "")).ToList());
I get:
cll
gtr
vln
dbl bss

Related

How to extract items at specified locations from list of comma separated strings using LINQ

I have a list of comma separated strings and I need to extract 1-st and 3-rd items from all strings.
List<string> list = new List<string>()
{
"1,2,3",
"4,5,6",
"7,8,9",
"10,11,12"
};
List<Tuple<string, string>> parsed = new List<Tuple<string, string>>(list.Count);
foreach (string s in list)
{
string[] items = s.Split(',');
parsed.Add(new Tuple<string, string>(items[0], items[2]));
}
Console.WriteLine(string.Join(Environment.NewLine, parsed.Select(p => p.Item1 +","+ p.Item2)));
Console.ReadLine();
That results:
1,3
4,6
7,9
10,12
But when I try to write it using LINQ, I can't get something simpler than:
IEnumerable<Tuple<string, string>> parsed = list.Select(
s =>
{
string[] items = s.Split(',');
return new Tuple<string, string>(items[0], items[2]);
});
I was wondering if it's possible to get rid of that {} block and replace it with LINQ function calls. To be clear, I am asking this question only to increase my knowledge of the features and capabilities of LINQ, so, any suggestion is welcome.
Edit:
So far, all suggested codes call the split function twice. Is there a way to get the desired result just by calling it once? Something like:
var parsed = list.Select(s => s.Split(',').Magic(...));
Also, by that code sample above, I didn't mean first and last items. I really mean items at specified locations.
If you are working with C#7 or above version, then you can write even in simpler manner,
IEnumerable<Tuple<string, string>> parsed = list.Select(
s => (s.Split(',')[0], s.Split(',')[2]));
You can do something like below
IEnumerable<Tuple<string, string>> parsed = list.Select(
s =>
{
var spl = s.Split(',');
return new Tuple<string, string>(spl[0], spl[2]);
// return new MyClass(spl[0], spl[2], ... ,spl[n]);
});
If you want the , separated list back by removing the middle number you can use the Regex to replace it.
IEnumerable<string> afterUpdate = list.Select(s => Regex.Replace(s, #",[0-9]*,", ","));
Output for this will be
{
"1,3",
"4,6",
"7,9",
"10,12"
};
May be this could help...
//----------------Linq.----------------------
//Data Source
var source = new List<string> { "1,2,3", "4,5,6", "7,8,9", "10,11,12" };
//var sourceTest = new List<string> { "11,45,6,5,", "2,3,4,5,6", "1,7,40,30", "10,20,30,40,50" };
//var sourceTest2 = new List<string> { "15,12,11,45,6,5,", "1,2,3,4,5,6", "1,7,9,40,30", "60,20,70,80,90,100" };
//Query Creation
var queryLambda = source.Select(item => new
{
FirstItem = item.Split(',').FirstOrDefault(),
ThirdItem = item.Split(',').Skip(2).FirstOrDefault()
}).ToList();
var query = (from items in source
select new
{
FirstItem = items.Split(',').FirstOrDefault(),
ThirdItem = items.Split(',').Skip(2).FirstOrDefault()
}).ToList();
//Query Execution
queryLambda.ForEach(item => { Console.WriteLine(string.Join(",", new string[] { item.FirstItem, item.ThirdItem })); });
Console.WriteLine();
query.ForEach(item => { Console.WriteLine(string.Join(",", new string[] { item.FirstItem, item.ThirdItem })); });
Console.ReadLine();

Removing strings with duplicate letters from string array

I have array of strings like
string[] A = { "abc", "cccc", "fgaeg", "def" };
I would like to obtain a list or array of strings where any letter appears only one time. I means that "cccc", "fgaeg" will be removed from input array.
I managed to do this but I feel that my way is very messy, unnecessarily complicated and not efficient.
Do you have any ideas to improve this algorythm (possibliy replacing with only one Linq query)?
My code:
var goodStrings = new List<string>();
int i = 0;
foreach (var str in A)
{
var tempArr = str.GroupBy(x => x)
.Select(x => new
{
Cnt = x.Count(),
Str = x.Key
}).ToArray();
var resultArr = tempArr.Where(g => g.Cnt > 1).Select(f => f.Str).ToArray();
if(resultArr.Length==0) goodStrings.Add(A[i]);
i++;
}
You can use Distinct method for every array item and get items with count of distinct items equals to original string length
string[] A = { "abc", "cccc", "fgaeg", "def" };
var result = A.Where(a => a.Distinct().Count() == a.Length).ToList();
You'll get list with abc and def values, as expected

Splitting text and putting it into dictionary

I have text with 600 words and I'm supposed to delete every quotation marks, numbers(years, dates, ..), digits ,... I should only have words, and I have to put in into dictionary.
So I have tried to go through with for each loop and get the first letter and save it in a list. Then I split every row in a word.
e.g.:
You are pretty.
You
are
pretty
The problem there are words in a row they're still same but they shouldn't be same. I've tried to fix it but I couldn't find any solution.
public Dictionary<string, int> words = new Dictionary<string, int>();
public Dictionary<char, List<string>> firstletter = new Dictionary<char, List<string>>();
public Aufgabe(string filename)
{
string filler = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ";
foreach (char f in filler)
{
firstletter[f] = new List<string>();
}
Load(filename);
}
public void Load(string filename)
{
List<string> w = new List<string>();
StreamReader r = new StreamReader(filename);
while (!r.EndOfStream)
{
string row = r.ReadLine();
string[] parts = row.Split(' ');
string[] sonderzeichen = new string[] { "#", ",", ".", ";", "'", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "(", ")", "{",
"}", "!", "?", "/", "\"", "&", "+", "-", "–" };
string[] list = new string[parts.Length];
for (int i = 0; i < parts.Length; i++)
{
string a = parts[i];
foreach (string s in sonderzeichen)
{
if (s != "-")
{
a = a.Replace(s, string.Empty);
}
else
{
if (a.Length == 1)
{
a = string.Empty;
}
}
}
list[i] = a;
}
parts = list;
foreach (string a in parts)
{
if (words.ContainsKey(a))
{
words[a] += 1;
}
else
{
words.Add(a, 1);
}
string b = a.ToUpper();
if (b == "")
continue;
List<string> letter = firstletter[b[0]];
if (!letter.Contains(a))
{
letter.Add(a);
}
}
}
}
There are some things missing in the other answers:
No validation is done to check if the text is a word
Comparison should not be case-sensitive (i.e. spain, Spain and SPAIN should be considered the same word)
My solution:
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
string text = "The 'rain' in spain falls mainly on the plain. 07 November 2018 20:02:07 - 20180520 I said the Plain in SPAIN. 12345";
var dictionary = Regex.Split(text, #"\W+")
.Where(IsValidWord)
.GroupBy(m => m, comparer)
.ToDictionary(m => m.Key, m => m.Count(), comparer);
Method IsValidWord:
// logic to validate word goes here
private static bool IsValidWord(string text)
{
double value;
bool isNumeric = double.TryParse(text, out value);
// add more validation rules here
return !isNumeric;
}
EDIT
I noticed in your code that you have a Dictionary with the words grouped by first letter. This can be achieved like this (using the previous dictionary):
var lettersDictionary = dictionary.Keys.GroupBy(x => x.Substring(0, 1),
(alphabet, subList) => new {
Alphabet = alphabet,
SubList = subList.OrderBy(x => x, comparer).ToList()
})
.ToDictionary(m => m.Alphabet, m => m.SubList, comparer);
You can just split with a regex, then use LINQ to create your dictionary:
var dictionary = Regex.Split(text, #"\W+")
.GroupBy(m => m, StringComparer.OrdinalIgnoreCase) // Case-insensitive
.ToDictionary(m => m.Key, m => m.Count());
UPDATE
In applying to your example code, your task class could become something like this to build both dictionaries (and to consider case insensitive):
public class Aufgabe
{
const string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ";
public Dictionary<string, int> words;
public Dictionary<char, List<string>> firstletter;
public Aufgabe(string filename)
{
var text = File.ReadAllText(filename);
words = Regex.Split(text, #"\W+")
.GroupBy(m => m, StringComparer.OrdinalIgnoreCase)
.ToDictionary(m => m.Key, m => m.Count());
firstletter = ALPHABET.ToDictionary(a => a, // First-letter key
a => words.Keys.Where(m => a == char.ToUpper(m[0])).ToList()); // Words
}
}
Here is one way with Regex, note that case sensitivity has not been addressed
var text = "The 'rain' in spain falls mainly on the plain. I said the plain in spain";
var result = new Dictionary<string,string>();
Regex.Matches(text, #"[^\s]+")
.OfType<Match>()
.Select(m => Regex.Replace(m.Value, #"\W", string.Empty))
.ToList()
.ForEach(word =>
{
if (!result.ContainsKey(word))
result.Add(word, word);
});
result
This is almost certainly a job for regular expressions. \W+ splits your input string into words, defined as any character sequence of alphanumeric characters. See the documentation.
string sentence = "You are pretty. State-of-the-art.";
string[] words = Regex.Split(sentence, #"\W+");
foreach (string word in words)
{
if (word != "")
{
Console.WriteLine(word);
}
}

Lexicographically sorted list of lists of strings

Currently, I am trying to implement a code to generate frequent sequences. In doing so I need to get an in-place sort of a list of lists of strings as follows:
List<List<string>> myList = new List<List<string>>();
List<string> input1 = new List<string>() {"a", "b", "d"};
List<string> input2 = new List<string>() {"a", "b", "c"};
myList.Add(input1);
myList.Add(input2);
The output that I need is:
myList = {{"a","b","c"},{"a","b","d"}};
I have tried to use myList.Sort() but it raised a System.InvalidOperationException.
I am not that good with LINQ so I haven't used anything of the sort.
How about :
myList = myList.OrderBy(s => string.Join(string.Empty, s)).ToList();
The trick is to sort according to the string made by the concatenation of each element of the child list.
If you want to solve with Sort() you may use this approach
myList.Sort((x, y) => x.Zip(y,(l1,l2) => string.Compare(l1,l2)).FirstOrDefault(c => c != 0));
Otherwise I would concartenate all items into a single string and compare those.
This is less efficient because the string objects have to be created first.
myList = myList.OrderBy(string.Concat).ToList();
Sample: https://dotnetfiddle.net/1VmohI
You can try below code:
List<string> input1 = new List<string>() { "a", "b", "d" };
List<string> input2 = new List<string>() { "a", "b", "c" };
//Instead of adding input as List<string>, add it as string
string delimiter = ",";
var input1Str = input1.Aggregate((i, j) => i + delimiter + j);
var input2Str = input2.Aggregate((i, j) => i + delimiter + j);
var myListStr = new List<string>();
myListStr.Add(input1Str);
myListStr.Add(input2Str);
myListStr.Sort();
//Now you can convert it into List<List<string>>
List<List<string>> myList = myListStr.Select(x => x.Split(',').ToList()).ToList();
You can also use
myList = myList.OrderBy(arr => arr[0])
.ThenBy(arr => arr[1])
.ThenBy(arr => arr[2])
.ToList();

How to find the duplicates in the given string in c#

I want to find the duplicates for a given string, I tried for collections, It is working fine, but i don't know how to do it for a string.
Here is the code I tried for collections,
string name = "this is a a program program";
string[] arr = name.Split(' ');
var myList = new List<string>();
var duplicates = new List<string>();
foreach(string res in arr)
{
if (!myList.Contains(res))
{
myList.Add(res);
}
else
{
duplicates.Add(res);
}
}
foreach(string result in duplicates)
{
Console.WriteLine(result);
}
Console.ReadLine();
But I want to find the duplicates for the below string and to store it in an array. How to do that?
eg:- string aa = "elements";
In the above string i want to find the duplicate characters and store it in an array
Can anyone help me?
Linq solution:
string name = "this is a a program program";
String[] result = name.Split(' ')
.GroupBy(word => word)
.Where(chunk => chunk.Count() > 1)
.Select(chunk => chunk.Key)
.ToArray();
Console.Write(String.Join(Environment.NewLine, result));
The same princicple for duplicate characters within a string:
String source = "elements";
Char[] result = source
.GroupBy(c => c)
.Where(chunk => chunk.Count() > 1)
.Select(chunk => chunk.Key)
.ToArray();
// result = ['e']
Console.Write(String.Join(Environment.NewLine, result));
string name = "elements";
var myList = new List<char>();
var duplicates = new List<char>();
foreach (char res in name)
{
if (!myList.Contains(res))
{
myList.Add(res);
}
else if (!duplicates.Contains(res))
{
duplicates.Add(res);
}
}
foreach (char result in duplicates)
{
Console.WriteLine(result);
}
Console.ReadLine();
string is an array of chars. So, you can use your collection approach.
But, I would reccomend typed HashSet. Just load it with string and you'll get array of chars without duplicates, with preserved order.
take a look:
string s = "aaabbcdaaee";
HashSet<char> hash = new HashSet<char>(s);
HashSet<char> hashDup = new HashSet<char>();
foreach (var c in s)
if (hash.Contains(c))
hash.Remove(c);
else
hashDup.Add(c);
foreach (var x in hashDup)
Console.WriteLine(x);
Console.ReadKey();
Instead of a List<> i'd use a HashSet<> because it doesn't allow duplicates and Add returns false in that case. It's more efficient. I'd also use a Dictionary<TKey,Tvalue> instead of the list to track the count of each char:
string text = "elements";
var duplicates = new HashSet<char>();
var duplicateCounts = new Dictionary<char, int>();
foreach (char c in text)
{
int charCount = 0;
bool isDuplicate = duplicateCounts.TryGetValue(c, out charCount);
duplicateCounts[c] = ++charCount;
if (isDuplicate)
duplicates.Add(c);
}
Now you have all unique duplicate chars in the HashSet and the count of each unique char in the dictionary. In this example the set only contains e because it's three times in the string.
So you could output it in the following way:
foreach(char dup in duplicates)
Console.WriteLine("Duplicate char {0} appears {1} times in the text."
, dup
, duplicateCounts[dup]);
For what it's worth, here's a LINQ one-liner which also creates a Dictionary that only contains the duplicate chars and their count:
Dictionary<char, int> duplicateCounts = text
.GroupBy(c => c)
.Where(g => g.Count() > 1)
.ToDictionary(g => g.Key, g => g.Count());
I've shown it as second approach because you should first understand the standard way.
string name = "this is a a program program";
var arr = name.Split(' ').ToArray();
var dup = arr.Where(p => arr.Count(q => q == p) > 1).Select(p => p);
HashSet<string> hash = new HashSet<string>(dup);
string duplicate = string.Join(" ", hash);
You can do this through `LINQ
string name = "this is a a program program";
var d = name.Split(' ').GroupBy(x => x).Select(y => new { word = y.Key, Wordcount = y.Count() }).Where(z=>z.cou > 1).ToList();
Use LINQ to group values:
public static IEnumerable<T> GetDuplicates<T>(this IEnumerable<T> list)
{
return list.GroupBy(item => item).SelectMany(group => group.Skip(1));
}
public static bool HasDuplicates<T>(this IEnumerable<T> list)
{
return list.GetDuplicates().IsNotEmpty();
}
Then you use these extensions like this:
var list = new List<string> { "a", "b", "b", "c" };
var duplicatedValues = list.GetDuplicates();

Categories