我有一个简化的Completable
字符串,已经过排序。字符串couild包含数字(0-9)或字母(a-z)。在混合使用的情况下,自然排序顺序。我需要一种方法来验证这是否属实。
尝试使用linq技术:
"12345"
但也可能有降序排序。
那么有更好的方式
string items1 = "2349"; //sorted
string items2 = "2476"; //not sorted, 6<>7
bool sorted1 = Enumerable.SequenceEqual(items1.OrderBy(x => x), items1); //true
bool sorted2 = Enumerable.SequenceEqual(items2.OrderBy(x => x), items2); //false
检查字符串是否已排序?也许一些内置的解决方案?
答案 0 :(得分:6)
您的解决方案很好,非常易读。它的一个问题是需要对string
which is O(n * log(n))进行排序,这可以通过迭代string
而不对其进行排序来解决。
例如:
var firstDifs = items1.Zip(items1.Skip(1), (x, y) => y - x);
此Linq
会将第一个string
中的每2个项目投射到一个表示其差异的数字,因此,如果您有items1 = "1245"
,则输出将为:
firstDifs:
{1, 2, 1}
现在您需要做的就是验证firstDifs
是升序还是降序:
bool firstSorted = firstDifs.All(x => x > 0) || firstDifs.All(x => x < 0); //true
现在:
所以整个解决方案是 O(n) 。
请注意 使用简单的循环 会更有效率,如果第一个All
已返回false
,因为第3487项已更改它的方向(例如:1234567891),第二个All
将无条件运行,Zip
运行两次(直到All
需要的地方) - 因为All
和Linq
有两次迭代,所以我们懒洋洋地评估它们。
答案 1 :(得分:3)
需要reducer。在C#中,它是Enumerable.Aggregate。这是O(n)算法。
var query = "123abc".Aggregate(new { asceding = true, descending = true, prev = (char?)null },
(result, currentChar) =>
new
{
asceding = result.prev == null || result.asceding && currentChar >= result.prev,
descending = result.prev == null || result.descending && currentChar <= result.prev,
prev = (char?)currentChar
}
);
Console.WriteLine(query.asceding || query.descending );
答案 2 :(得分:2)
我曾经不得不检查类似于你的情况,但是有大量的数据流,所以性能很重要。我想出了这个小扩展课程,表现非常好:
public static bool IsOrdered<T>(this IEnumerable<T> enumerable) where T: IComparable<T>
{
using (var enumerator = enumerable.GetEnumerator())
{
if (!enumerator.MoveNext())
return true; //empty enumeration is ordered
var left = enumerator.Current;
int previousUnequalComparison = 0;
while (enumerator.MoveNext())
{
var right = enumerator.Current;
var currentComparison = left.CompareTo(right);
if (currentComparison != 0)
{
if (previousUnequalComparison != 0
&& currentComparison != previousUnequalComparison)
return false;
previousUnequalComparison = currentComparison;
left = right;
}
}
}
return true;
}
使用它显然很简单:
var items1 = "2349";
var items2 = "2476"; //not sorted, 6<>7
items1.IsOrdered(); //true
items2.IsOrdered(); //false
答案 3 :(得分:1)
通过不必比较所有元素,你可以比接受的答案做得更好:
var s = "2349";
var r = Enumerable.Range(1, s.Length - 1);
//var isAscending = r.All(i => s[i - 1] <= s[i]);
//var isDescending = r.All(i => s[i - 1] >= s[i]);
var isOrdered = r.All(i => s[i - 1] <= s[i]) || r.All(i => s[i - 1] >= s[i]);
答案 4 :(得分:0)
var items = "4321";
var sortedItems = items.OrderBy(i => i); // Process the order once only
var sorted = sortedItems.SequenceEqual(items) || sortedItems.SequenceEqual(items.Reverse()); // Reverse using yield return
答案 5 :(得分:0)
我会对所有元素进行简单的迭代:
string str = "whatever123";
Func<char, char, bool> pred;
bool? asc = str.TakeWhile((q, i) => i < str.Length - 1)
.Select((q, i) => str[i] == str[i+1] ? (bool?)null : str[i] < str[i+1])
.FirstOrDefault(q => q.HasValue);
if (!asc.HasValue)
return true; //all chars are the same
if (asc.Value)
pred = (c1, c2) => c1 <= c2;
else
pred = (c1, c2) => c1 >= c2;
for (int i = 0; i < str.Length - 1; ++i)
{
if (!pred(str[i], str[i + 1]))
return false;
}
return true;