Find List<T> second to last element - c#-4.0

I would like to find the second to the last item in a list. One article came up with the search terms I used and they suggested getting the index of the last element then backing up one step. Is this really the way to do it....? Seems kinda kludgy / hard coded. Perhaps I'm being too paranoid??
int _lstItemIdx = List<MyObj>.IndexOf(List<MyObj>.Last());
int _sndLstItmIdx = (_lstItemIdx - 1);
Thank You

What's wrong with:
var result = myList[myList.Count-2];
Of course, you need appropriate exception handling in case your list doesn't have 2 elements.
And you can turn it into an extension method:
public static T SecondToLast<T>(this IList<T> source)
{
if (source.Count < 2)
throw new ArgumentException("The list does not have at least 2 elements");
return source[source.Count - 2];
}

Related

Find position of item in list using Binary Search

The question is:
Given a list of String, find a specific string in the list and return
its index in the ordered list of String sorted by mergesort. There are
two cases:
The string is in the list, return the index it should be in, in the ordered list.
The String is NOT in the list, return the index it is supposed to be in, in the ordered list.
Here is my my code, I assume that the given list is already ordered.
For 2nd case, how do I use mergesort to find the supposed index? I would appreciate some clues.
I was thinking to get a copy of the original list first, sort it, and get the index of the string in the copy list. Here I got stuck... do I use mergesort again to get the index of non-existing string in the copy list?
public static int BSearch(List<String> s, String a) {
int size = s.size();
int half = size / 2;
int index = 0;
// base case?
if (half == 0) {
if (s.get(half) == a) {
return index;
} else {
return index + 1;
}
}
// with String a
if (s.contains(a)) {
// on the right
if (s.indexOf(s) > half) {
List<String> rightHalf = s.subList(half + 1, size);
index += half;
return BSearch(rightHalf, a);
} else {
// one the left
List<String> leftHalf = s.subList(0, half - 1);
index += half;
return BSearch(leftHalf, a);
}
}
return index;
}
When I run this code, the index is not updated. I wonder what is wrong here. I only get 0 or 1 when I test the code even with the string in the list.
Your code only returns 0 or 1 because you don't keep track of your index for each recursive call, instead of resetting to 0 each time. Also, to find where the non-existent element should be, consider the list {0,2,3,5,6}. If we were to run a binary search to look for 4 here, it should stop at the index where element 5 is. Hope that's enough to get you started!

can we perform binary search on linked lists?

there was a reputed site which claimed that we cannot do binary search on linked list but I know for a fact that we can perform merge sort( which uses divide and conquer just like binary search) on a linked list so we must be able to perform binary search on a linked list as well right??
Purely in the abstract, a linked list does not support direct indexing. The only way to get to the third element is by starting at the first element, following the next link to the second element, then following it's next link to the third element.
If the implementation allows for indexing (e.g., java.util.LinkedList), it is possible to implement a binary search by calling get(index) when you need an element. If the underlying data structure is a simple linked list without an auxiliary lookup structure, then this will perform very poorly. As an example, the following is the code from the OpenJDK java.util.LinkedList.get method.
package java.util;
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
public E get(int index) {
return node(index).item;
}
Node<E> node(int index) {
if (index < (size >> 2)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
}
When list.get(5) is called to get the sixth element in a list of more than 11 elements, it iterates over the first five elements before returning the sixth. The generic interface provides indexed access into the sequence but makes no guarantees on its performance.

Linq to split/analyse substrings

I have got a List of strings like:
String1
String1.String2
String1.String2.String3
Other1
Other1.Other2
Test1
Stuff1.Stuff1
Text1.Text2.Text3
Folder1.Folder2.FolderA
Folder1.Folder2.FolderB
Folder1.Folder2.FolderB.FolderC
Now I would like to group this into:
String1.String2.String3
Other1.Other2
Test1
Stuff1.Stuff1
Text1.Text2.Text3
Folder1.Folder2.FolderA
Folder1.Folder2.FolderB.FolderC
If
"String1" is in the next item "String1.String2" I will ignore the first one
and if the second item is in the third I will only take the third "String1.String2.String3"
and so on (n items). The string is structured like a node/path and could be split by a dot.
As you can see for the Folder example Folder2 has got two different Subfolder items so I would need both strings.
Do you know how to handle this with Linq? I would prefer VB.Net but C# is also ok.
Regards Athu
Dim r = input.Where(Function(e, i) i = input.Count - 1 OrElse Not input(i + 1).StartsWith(e + ".")).ToList()
Condition within Where method checks if element is last from input or is not followed by element, that contains current one.
That solution uses the fact, that input is List(Of String), so Count and input(i+1) are available on O(1) time.
LINQ isn't really the correct approach here, because you need to access more than one item at a time.
I would go with something like this:
public static IEnumerable<string> Filter(this IEnumerable<string> source)
{
string previous = null;
foreach(var current in source)
{
if(previous != null && !current.Contains(previous))
yield return previous;
previous = current;
}
yield return previous;
}
Usage:
var result = strings.Filter();
Pretty simple one. Try this:
var lst = new List<string> { /*...*/ };
var sorted =
from item in lst
where lst.Last() == item || !lst[lst.IndexOf(item) + 1].Contains(item)
select item;
the following simple line can do the trick, I'm not sure about the performance cost through
List<string> someStuff = new List<string>();
//Code to the strings here, code not added for brewity
IEnumerable<string> result = someStuff.Where(s => someStuff.Count(x => x.StartsWith(s)) == 1);

Count of nodes in BST

I am trying to count the number of nodes in a Binary Search Tree and was wondering what the most efficient means was. These are the options that I have found:
store int count in the BST Class
store int children in each node of the tree which stores the number of children under it
write a method that counts the number of Nodes in the BST
if using option 3, I've written:
int InOrder {
Node *cur = root;
int count = 0;
Stack *s = null;
bool done = false;
while(!done) {
if(cur != NULL) {
s.push(cur);
cur = cur->left;
}
else {
if(!s.IsEmpty()) {
cur = s.pop();
count++;
cur = cur->right;
}
else {
done = true;
}
}
}
return count;
}
but from looking at it, it seems like it would get stuck in an infinite loop between cur = cur->left; and cur = cur->right;
So which option is the most efficient and if it is option 3, then will this method work?
I think the first option is the quickest and it only requires O(1) space to achieve this. However whenever you insert/delete an item, you need to keep updating this value.
It will take O(1) time to get the number of all the nodes.
The second option would make this program way too complicated since deleting/inserting a node somewhere would have to update all of its ancestors. Either you add a parent pointer so you can adequately update each one of the ancestors, or you need to go through all the nodes in the tree and update the numbers again. Anyway I think this would be the worst option of all three.
The third option is good if you don't call this many times since the first option is a lot quicker, O(1), than this option. This will take O(n) since you need to go through every single node to check the count.
In terms of your code, I think it's easier to write in a recursive way like below:
int getCount(Node* n)
{
if (!n)
return 0;
return 1 + getCount(n->left) + getCount(n->right);
}
Hope this helps!

Is there a .NET function to remove the first (and only the first) occurrence at the start of a string?

I was using the TrimStart function to do the following:
var example = "Savings:Save 20% on this stuff";
example = example.TrimStart("Savings:".ToCharArray());
I was expecting this to result in example having a value of "Save 20% on this stuff".
However, what I got was "e 20% on this stuff".
After reading the documentation on TrimStart I understand why, but now I'm left wondering if there is a function in .NET that does what I was trying to do in the first place?
Does anyone know of a function so I don't have to create my own and keep track of it?
I don't think such a method exists but you can easily do it using StartsWith and Substring:
s = s.StartsWith(toRemove) ? s.Substring(toRemove.Length) : s;
You can even add it as an extension method:
public static class StringExtension
{
public static string RemoveFromStart(this string s, string toRemove)
{
if (s == null)
{
throw new ArgumentNullException("s");
}
if (toRemove == null)
{
throw new ArgumentNullException("toRemove");
}
if (!s.StartsWith(toRemove))
{
return s;
}
return s.Substring(toRemove.Length);
}
}
No, I don't believe there's anything which does this built into the framework. It's a somewhat unusual requirement, IMO.
Note that you should think carefully about whether you're trying to remove "the first occurrence" or remove the occurrence at the start of the string, if there is one. For example, think what you'd want to do with: "Hello. Savings: Save 20% on this stuff".
You can do that quite easily using a regular expression.
Remove the occurrence on the beginning of the string:
example = Regex.Replace(example, #"^Savings:", "");
Remove the first occurrence in the string:
example = Regex.Replace(example, #"(?<!Savings:.*)Savings:", "");

Resources