C# How to find out if array includes string twice - c#

i want to check if a string array includes a string more than one time.
for example
string[] array = new string[]{"A1","A2","A3"};
string item = "A1";
look for item in array, include item just once return false
string[] array = new string[]{"A1","A2","A3","A1"};
string item = "A1";
return true
Any insight would be greatly appreciated.

If you want to know whether or not a particular item is repeated more than once, you can get the count of the item and check if it is bigger than 1:
bool isRepeated = array.Count(x => x == item) > 1;
Or, you can do it more efficiently with a HashSet:
bool isRepeated = false;
var set = new HashSet<int>();
foreach(var x in array)
{
if(x == item && !set.Add(x))
{
isRepeated = true;
break;
}
}

Related

Formatting List of String

I have an array of strings. I need to sort the list and save each letter's item in a single line. After this, I need to find the longest line of string.
I have done the first part in an inefficient way but I am trying to make it concise.
List<string> fruits = new List<string>
{
"Pomme",
"Apple",
"Apricots",
"Avocado",
"Banana",
"Blackberries",
"Blackcurrant",
"Blueberries",
"Cherries",
"Clementine",
"Cranberries",
"Custard-Apple",
"Durian",
"Elderberries",
"Feijoa",
"Figs",
"Gooseberries",
"Grapefruit",
"Grapes",
"Guava",
"Breadfruit",
"Cantaloupe",
"Carambola",
"Cherimoya",
};
fruits.Sort();
List<string> sortedString = new List<string> { };
foreach (var str in fruits)
{
sortedString.Add(str);
}
//string A, B, C, D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S;
var A = "";
var B = "";
var C = "";
var D = "";
var E = "";
var F = "";
var G = "";
foreach (var item in sortedString)
{
if (item.StartsWith('A'))
{
A += item;
}
else if (item.StartsWith('B'))
{
B += item;
}
else if (item.StartsWith('C'))
{
C += item;
}
else if (item.StartsWith('D'))
{
D += item;
}
else if (item.StartsWith('E'))
{
E += item;
}
else if (item.StartsWith('F'))
{
F += item;
}
}
The result will be like -
AppleApricotsAvocado
BananaBlackberriesBlackcurrantBlueberriesBreadfruit
CantaloupeCarambolaCherimoyaCherriesClementineCranberriesCustard-Apple
Durian
Elderberries
FeijoaFigs
GooseberriesGrapefruitGrapesGuava
After this, I need to find the longest line and put space between each item. Without effective looping, the code will be messy. Can you assist me to show the right way to solve the problem?
The Sort() method already sorts your list and you don't need to assign it to a new one.
My proposal to resolve your problem is
fruits.Sort();
var result = fruits.GroupBy(f => f[0]);
int[] lineslength = new int[result.Count()];
int index = 0;
foreach (var group in result)
{
foreach (var item in group)
{
lineslength[index] += item.Length;
Console.Write(item + " ");
}
Console.WriteLine();
index++;
}
int longestIndex = Array.FindIndex(lineslength, val => val.Equals(lineslength.Max()));
Console.WriteLine(longestIndex);
I used the GroupBy method to group strings by their first letter. Then when I was displaying strings I also counted their length. Using the static FindIndex method of the Array class, I found the index containing the maximum value of the array what corresponds to the line with the maximum length. So index zero is the first line, one is the second line etc.

How to find the placement of a List within another List?

I am working with two lists. The first contains a large sequence of strings. The second contains a smaller list of strings. I need to find where the second list exists in the first list.
I worked with enumeration, and due to the large size of the data, this is very slow, I was hoping for a faster way.
List<string> first = new List<string>() { "AAA","BBB","CCC","DDD","EEE","FFF" };
List<string> second = new List<string>() { "CCC","DDD","EEE" };
int x = SomeMagic(first,second);
And I would need x to = 2.
Ok, here is my variant with old-good-for-each-loop:
private int SomeMagic(IEnumerable<string> source, IEnumerable<string> target)
{
/* Some obvious checks for `source` and `target` lenght / nullity are ommited */
// searched pattern
var pattern = target.ToArray();
// candidates in form `candidate index` -> `checked length`
var candidates = new Dictionary<int, int>();
// iteration index
var index = 0;
// so, lets the magic begin
foreach (var value in source)
{
// check candidates
foreach (var candidate in candidates.Keys.ToArray()) // <- we are going to change this collection
{
var checkedLength = candidates[candidate];
if (value == pattern[checkedLength]) // <- here `checkedLength` is used in sense `nextPositionToCheck`
{
// candidate has match next value
checkedLength += 1;
// check if we are done here
if (checkedLength == pattern.Length) return candidate; // <- exit point
candidates[candidate] = checkedLength;
}
else
// candidate has failed
candidates.Remove(candidate);
}
// check for new candidate
if (value == pattern[0])
candidates.Add(index, 1);
index++;
}
// we did everything we could
return -1;
}
We use dictionary of candidates to handle situations like:
var first = new List<string> { "AAA","BBB","CCC","CCC","CCC","CCC","EEE","FFF" };
var second = new List<string> { "CCC","CCC","CCC","EEE" };
If you are willing to use MoreLinq then consider using Window:
var windows = first.Window(second.Count);
var result = windows
.Select((subset, index) => new { subset, index = (int?)index })
.Where(z => Enumerable.SequenceEqual(second, z.subset))
.Select(z => z.index)
.FirstOrDefault();
Console.WriteLine(result);
Console.ReadLine();
Window will allow you to look at 'slices' of the data in chunks (based on the length of your second list). Then SequenceEqual can be used to see if the slice is equal to second. If it is, the index can be returned. If it doesn't find a match, null will be returned.
Implemented SomeMagic method as below, this will return -1 if no match found, else it will return the index of start element in first list.
private int SomeMagic(List<string> first, List<string> second)
{
if (first.Count < second.Count)
{
return -1;
}
for (int i = 0; i <= first.Count - second.Count; i++)
{
List<string> partialFirst = first.GetRange(i, second.Count);
if (Enumerable.SequenceEqual(partialFirst, second))
return i;
}
return -1;
}
you can use intersect extension method using the namepace System.Linq
var CommonList = Listfirst.Intersect(Listsecond)

Find the highest ranked item of a list from another list

I have a list of items already ordered by highest rank that I store in variable topList.
Then I have current list of items that I store in variable currentList
The goal is to find the element of currentList who is the highest ranked in topList.
[TestMethod]
public void MethodName14() {
var topList = new List<string>() {"AB", "DC", "ZG"}; // ordered by highest rank
var currentList = new List<string> {"ZG", "DC"};
var actual = ReturnTop(currentList, topList);
Assert.Equal("DC", actual); // because DC is in index 2 and ZG is in index 3
}
private string ReturnTop(List<string> currentList, List<string> topList) {
string result = null;
int index = 0;
foreach (var current in currentList) {
var lookupedCurrentIndex = topList.FindIndex(a => a == current);
if (index == 0) {
result = topList[index];
index = lookupedCurrentIndex;
} else {
if (lookupedCurrentIndex < index) {
index = lookupedCurrentIndex;
result = topList[index];
}
}
}
return result;
}
My method ReturnTop is too slow, it's O(n²). Can we do better ?
Your current implementation is O(N*T), where N is the number of items in your query list, and T is the number of items in the top list; it is O(1) in use of space.
If you do not mind increasing the use of space to O(N), you can implement an algorithm in O(N+T) by constructing a hash set from query words, and searching for the first word in topList that matches one of query words, as follows:
var knownWords = new HashSet<string>(currentList);
return topList.FirstOrDefault(w => knownWords.Contains(w));
Constructing knownWords takes O(N) time and O(N) space. Searching topList for the earliest item that exists in knownWords takes O(T) time and O(1) space, because hash set look-up is O(1).
This can be further shortened to this (thank you, Slai!)
return topList.Intersect(currentList).FirstOrDefault();
var topList = new List<string>() {"AB", "DC", "ZG"}; // ordered by highest rank
var currentList = new List<string> {"ZG", "DC"};
var bestItem = currentList.OrderBy(item => topList.FindIndex(a => a == item)).FirstOrDefault();
Console.WriteLine(bestItem);
http://csharppad.com/gist/b6f3b41afb86018c6f81284cc4ae22b5
With solution below searching of top item will take O(N + M)(where N is amount of topList items and M is amount of current list) which can be count as O(2N)
It will loop once all items of topList while creating a dictionary.
And will loop once all items of current for searching item with min index.
private string ReturnTop(IEnumerable<string> current, IEnumerable<string> topList)
{
var topMap = topList.Select((value, index) => new {Value = value, Index = index})
.ToDictionary(item => item.Value, item => item.Index);
string minItem = null;
int minPosition = topMap.Count;
foreach (var item in current)
{
var currentPosition = topMap[item];
if (currentPosition == 0)
{
return item;
}
if (currentPosition < minPosition)
{
minPosition = currentPosition;
minItem = item;
}
}
return minItem;
}

C# Finding elements from a list to match each elements from another list

The idea is that I have an object GrossPanel that has a property GrossPanel.PanelListthat contains a list of Panelobjects ;List<Panel>
Each Panelobject has the property of type double Panel.Prod_Width
What I want to do is to match each Panel.Prod_Widthin the inputto each Panel.Prod_Widthin the template.PanelList
When a match is found, the Panelfrom the inputlist is put into a new GrossPanelobject and removed frominput. If a complete matching set is found the resulting GrossPanelis added to the _Returnlist and everyting is repeated until the input list is exhausted.
Example:
Lets say the inputcontains 9 elements (Panel0-Panel8) and templatecontains 2 elements (temp0-temp1)
Panel0-Panel3 has Prod_Width = 200
Panel4-Panel7 has Prod_Width = 300
Panel8 has Prod_Width = 400
temp0 has Prod_Width = 200 and temp1 has Prod_Width = 300
This should create 4 GrossPanelobjects, GP0-GP3
GP0 should contain Panel0 and Panel4
GP1 should contain Panel1 and Panel5
GP2 should contain Panel2 and Panel6
GP3 should contain Panel3 and Panel7
Panel8 can't be used
This is the code I have written to do this. It works, but it is very slow.
Is there a way to do this more efficient? I tried to do a foreach loop and removing elements from inputalong the way, but it din't work. Instead I use Indexand _index to skip the "used" elements in input
private static List<GrossPanel> Match (List<Panel> input, GrossPanel template)
{
List<Panel> _template = template.PanelList.OrderBy(panel => panel.Prod_Width).ToList();
List<Panel> _input = input.OrderBy(panel => panel.Prod_Width).ToList();
List<GrossPanel> _Returnlist = new List<GrossPanel>();
List<int> indexlist = new List<int>(); // list of used indexes
int Index = 0; //counting the panels you have checked
while (Index < _input.Count)
{
int _index = 0;
GrossPanel Grosspanel = new GrossPanel();
for (int templateindex = 0; templateindex < _template.Count(); templateindex++)
{
for (int inputindex = _index; inputindex < _input.Count(); inputindex++)
{
if ((!indexlist.Contains(inputindex)) && (_template.ElementAt(templateindex).Prod_Width == _input.ElementAt(inputindex).Prod_Width))
{
indexlist.Add(inputindex);
Grosspanel.AddNetPanel(input.ElementAt(inputindex));
_index = indexlist.Last(); //
Index++;
break;
}
}
}
if (Grosspanel.NetPanelCount == _template.Count()) _Returnlist.Add(Grosspanel);
else if (Grosspanel.NetPanelCount != _template.Count()) Index = _input.Count;
}
return _Returnlist;
}
OK...
I tried to use IEnuberable and yield return to make this quicker. My problem now is that when I find a match in input I can't seem to remove it from input in the next iteration.
here is the code
private static IEnumerable<GrossSteniPanel> Match (IEnumerable<Panel> input, GrossPanel template, List<Panel> usedpanels, int index)
{
GrossPanel Grosspanel;
List<Panel> _usedpanels = new List<Panel>();
IEnumerable<Panel> _input = input;
_input = _input.Except(usedpanels);
if (index < 0 | (_input.Count() == 0)) yield return Grosspanel = new GrossPanel();
else
{
foreach (Panel p in _input)
{
if (p.Prod_Width == template.NetPanelList.ElementAt(index).Prod_Width)
{
_usedpanels.Add(p);
_input = _input.Except(_usedpanels);
foreach (GrossPanel panel in Match (_input, template, usedpanels, index - 1))
{
Grosspanel = panel;
Grosspanel.AddNetPanel(p);
yield return Grosspanel;
}
}
}
}
}
What am I missing??
My recommendations:
Try to make your code easier to read and understand (in 99% of the cases this is more important than performance).
Use one convention when naming variables. I found 4 different naming conventions in first 5 lines of "Match" method.
Using underline before local variable name is not good.
try to write tests for "Match" method.
Refactor example (name "Match" changed to "BuildGrossPanelList"):
static IList<GrossPanel> BuildGrossPanelList(List<Panel> input, GrossPanel template)
{
var templatePanels = template.PanelList
.OrderBy(panel => panel.Width);
var inputPanels = input
.OrderBy(panel => panel.Width)
.ThenBy(panel => panel.Id);
// If `input` can have elements with the same `panel.Width`
// and you want to always retun the same result then the sorting has to be extend.
var templatesWithMatchingPanels = templatePanels
.ToDictionary(
tp => tp,
tp => inputPanels.Where(p => p.Width == tp.Width).ToList());
return GetGrossPanels(templatesWithMatchingPanels);
}
static IList<GrossPanel> GetGrossPanels(Dictionary<Panel, List<Panel>> templatesWithMatchingPanels)
{
var result = new List<GrossPanel>();
while(AnyNotUsedPanelExistsForEveryTemplate(templatesWithMatchingPanels))
{
result.Add(CreateNewGrossPanel(templatesWithMatchingPanels));
}
return result;
}
static bool AnyNotUsedPanelExistsForEveryTemplate(Dictionary<Panel, List<Panel>> templatesWithMatchingPanels)
{
return templatesWithMatchingPanels.All(entry => entry.Value.Any());
}
static GrossPanel CreateNewGrossPanel(Dictionary<Panel, List<Panel>> templatesWithMatchingPanels)
{
var result = new GrossPanel();
foreach(var templatePanelEntry in templatesWithMatchingPanels)
{
var firstMatchingPanel = GetAndRemoveFirst(templatePanelEntry.Value);
result.AddNetPanel(firstMatchingPanel);
}
return result;
}
static Panel GetAndRemoveFirst(IList<Panel> panels)
{
var result = panels.First();
panels.RemoveAt(0);
return result;
}
If "Match" method is part of a large class at least put the above code in a nested class. Consider creating a new class in a separate file. Methods in this new class wouldn't have to be static.

Searching an array with foreach loop and getting the index of element

I have a class like so:
public class MyClass
{
public char letter { get; set; }
public double result { get; set; }
public bool test { get; set; }
}
I declare an array:
MyClass[] myArray = new MyClass[counter];
and fill it with some data.
I sort the array:
myArray = myArray.OrderBy(a => a.letter).ThenByDescending(a => a.result).ToArray();
Now let's say I have an int i = 100 variable.
How would I iterate through this array fields and get the index of the first element that:
Has specified letter in letter field.
Has test == false
result < i
I'm thinking of something like this:
foreach(MyClass t in myArray.Where(a => a.letter == 'a')
{
if(t.result < i && t.test == false) get index of that field
}
However, I'm unsure how to get the index of it. How do I do this?
Array.FindIndex should solve the problem for you:
int correctIndex = Array.FindIndex( myArray , item => item.letter == 'a' && item.result < i && !item.test );
The second parameter is functionally equivalent to how you would describe it in a .Where() clause.
Also, just like similar indexing functions, it returns -1 if the element isn't found.
You can do it using the overload of Select that provides an index, like this:
var res = myArray
.Select((val, ind) => new {val, ind}))
.Where(p => p.val.result < i && p.val.letter == 'a' && !p.val.test)
.Select(p => p.ind);
The first Select pairs up MyClass objects, as val, with their index, as ind. Then the Where method expresses the three conditions, including the one that pairs result and ind. Finally, the last Select drops the MyClass object, because it is no longer needed.
I see the guys already did a great job answering your question with better alternatives, but just in case you still want to know how to do it with for each, here is how
int counter = 5 ; // size of your array
int i = 100 ; // the limit to filter result by
int searchResult = -1; // The index of your result [If exists]
int index = 0; // index in the array
MyClass[] myArray = new MyClass[counter]; // Define you array and fill it
myArray[0] = new MyClass {letter = 'f' ,result = 12.3 , test = false } ;
myArray[1] = new MyClass {letter = 'a' ,result = 102.3 , test = true} ;
myArray[2] = new MyClass {letter = 'a' ,result = 12.3 , test = false } ;
myArray[3] = new MyClass {letter = 'b' ,result = 88 , test = true } ;
myArray[4] = new MyClass { letter = 'q', result = 234, test = false };
myArray = myArray.OrderBy(a => a.letter).ThenByDescending(a => a.result).ToArray(); // Sort the array
foreach(MyClass t in myArray.Where(a => a.letter == 'a')) // The foreach part
{
if (t.result < i && t.test == false)
{
searchResult = index;
break;
}
index++;
}
// And finally write the resulting index [If the element was found]
Please note : Of course the resulting index will be the index in the sorted array
Without foreach:
var item = myArray.FirstOrDefault(e => e.letter == 'a' && e.result < i && e.test == false);
int index = Array.IndexOf(myArray, item);

Categories