Orderless pattern matching of rule lists

Edit: see the bottom of this answer for my proposed solution.

Can you be sure your rule list is well formed, meaning that it is in fact a valid list of rules? I can think of a number of ways to approach this problem if that is the case. For example using Intersection:

{"a", "b"} === ruleList2[[All, 1]] ⋂ {"a", "b"}
True

Or using OptionValue:

2 == Length @ OptionValue[ruleList2, {"a", "b"}]
True

You could also sort the list Peltio suggested. This can be done somewhat automatically by using a head with the Orderless attribute:

SetAttributes[o, Orderless];

MatchQ[o @@ ruleList2, o["a" -> _, "b" -> _, ___]]
True

Timings

Peltio questioned the efficiency of using Orderless and he was right to do so; on longer lists it is slower than the original method. Here are comparative timings performed in version 7. I left out the OptionValue method as it failed with errors; I need to look into that.

SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] :=
  Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

rules = Rule @@@ RandomInteger[1000, {500, 2}];

{a, b} = {277, 514};

MatchQ[rules, {___, a -> _, ___, b -> _, ___} | {___, b -> _, ___, a -> _, ___}] // timeAvg
MatchQ[Sort@rules, {___, a -> _, ___, b -> _, ___}] // timeAvg
MatchQ[o @@ rules, o[a -> _, b -> _, ___]]          // timeAvg
{a, b} === rules[[All, 1]] ⋂ {a, b}                 // timeAvg

0.262

0.131

0.702

0.000093888

So on this sample pre-sorting cuts the time in half, whereas using Orderless nearly triples it. Intersection however is more than three orders of magnitude faster than any of the others.

Even better and more robust (in the case that the list contains expressions other than rules) appears to be using FilterRules before Intersection:

{a, b} === {a, b} ⋂ FilterRules[rules, {a, b}][[All, 1]] // timeAvg
0.000028928

Proposed solution

Therefore, I propose using this:

ruleMatch[rules_List, keys_List] := 
  Union @ keys === keys ⋂ FilterRules[rules, keys][[All, 1]]

Example:

ruleMatch[#, {"a", "b"}] & /@ {ruleList1, ruleList2}
{True, True}

One way would be to explicitly wrap both a list and a pattern in an Orderless container:

ClearAll[cont];
SetAttributes[cont, Orderless];
MatchQ[cont @@ ruleList1, cont["a" -> _, "b" -> _, ___]]

(* True *)

OrderlessPatternSequence

MatchQ[#, {OrderlessPatternSequence[___,"a" -> _, ___, "b" -> _, ___]}] & /@
   {ruleList1, ruleList2}

{True, True}

MatchQ[#, {OrderlessPatternSequence[___,"b" -> _, ___, "a" -> _, ___]}] & /@
   {ruleList1, ruleList2}

{True, True}