This is a rather more general solution, so in that respect it might not be what you are after, but it should redirect the URLs in your question.
RewriteRule ^(\d)\.(html|asp)$ /dir/$1.html [R=301,L]
RewriteRule ^(\d)_([a-z])\.html$ /dir/sub/$1-$2.html [R=301,L]
RewriteRule will match any single digit URL eg.
7.asp and redirect to
/dir/7.html respectively. The
$1 backreference matches the first parenthesised sub pattern in the pattern that is matched.
RewriteRule matches a URL that contains a single digit followed by an underscore and then a single lowercase letter. The underscore is replaced with a hyphen in the redirect. eg.
6_g.html is redirected to
Alternative (more restrictive) version
If a more restrictive version is required that only matches the specific URLs stated in the question then you could do something like the following instead. Although it is arguably more "complex"...
RewriteRule ^()\.html|()\.asp$ /dir/$1$2.html [R=301,L]
RewriteRule ^(4)_([ab])\.html$ /dir/sub/$1-$2.html [R=301,L]
The first rule would perhaps be easier to read if it was split into two. The two backreferences
$2 in the first rule are mutually exclusive, when one is set, the other is empty, hence the presence of both in the substitution string.
If you are not already using mod_rewrite elsewhere in your
.htaccess then mod_alias
RedirectMatch directives may be preferable, although this does make the regex marginally more complex because of the slash prefix that needs to be matched...
RedirectMatch 301 ^/(?:()\.html|()\.asp)$ /dir/$1$2.html
RedirectMatch 301 ^/(4)_([ab])\.html$ /dir/sub/$1-$2.html