Post #178,281
10/7/04 3:55:53 PM
|
Perl frustrations
I'm trying to do what ought to be a blood simple thing and I've been at it a couple hours now with no success. I have a denormalized hash:
my %den = { "one" => "a", "two" => "b", "three" => "c", "four" => "b", "five" => "c", "six" => "a", "seven" => "b" };
I wish to invert it such that I end up with something like:
my %norm { "a" => ("one", "six), ... }
I've started with this: #hash of empty lists my %norm = { "a" => (), "b" => (), "c" => () };
while((my $key,my $val) = each %den) { my @list = $norm{$val}; #get the list push @list, $key; #append to it }
This does not work. I do not have any idea why.
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #178,286
10/7/04 4:37:44 PM
10/7/04 5:31:13 PM
|
Simple solution
If there are no duplicates, you can do this: my %norm = reverse %dem; Of course in general there are, so you have to be more careful: \nmy %norm;\nwhile( my ($key, $val) = each %den) {\npush @{ $norm{$val} }, $key;\n}\n Voila!
The problem in your code is that you keep on switching between hashes and arrays, and references to hashes or arrays. You can't do that in Perl. Also you have to always look at how lists expand. So, for instance, you write: \nmy %norm =\n{\n"a" => (),\n"b" => (),\n"c" => ()\n};\n all of those ()s get expanded to nothing, Perl actually sees, \nmy %norm =\n{\n"a",\n"b",\n"c"\n};\n which is \nmy %norm =\n{\n"a" => "b",\n"c" => undef,\n};\n and - even worse - {} constructs a reference to a hash so that is assigned as the key of a hash. So you wind up actually with something like: \nmy %norm = ('HASH(0x815dba8) => undef);\n (The address of the hash will vary - but it doesn't matter since you didn't keep a reference to it so it got unallocated.) In the same way if you say: \nmy @list = $norm{$val};\n what you get is an array with a reference to an array in it. (Actually with undef rather than a reference to an array since %norm didn't have what you expect.) You then append to @list in the next line, but that doesn't do anything because then @list gets discarded. So your code is going to wind up with %norm having one unexpected key and no values. For playing around with this kind of thing, I strongly recommend using Data::Dumper. Something like this would have helped you see what is happening: \nuse Data::Dumper;\nprint Dumper(\\%norm);\n Cheers, Ben PS For a lot of problems like this, the Perl Cookbook has useful recipies. I highly recommend using it as a reference until your brain starts "getting" how Perl is supposed to work. EDIT I simplified the real solution slightly by getting rid of a superfluous my.
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
Edited by ben_tilly
Oct. 7, 2004, 05:31:13 PM EDT
|
Post #178,288
10/7/04 4:42:49 PM
|
Bleh.
Perl never seems to do what I expect it to do...
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #178,298
10/7/04 5:22:57 PM
|
That's because you approached it wrong
I'm serious.
Perl was designed as a "better shell, with a few things integrated in" and all of the "BTW its now a real programming language" stuff was later shoehorned on top. So if you use it as a "better shell, with a few things integrated in", it tends to work out well and it doesn't take you long to train your intuition about what Perl's "grammar" looks like. And once your intuition is trained by that, the real programming stuff fits in surprisingly well.
But if you approach it as a real programming language right off of the bat, you're going to keep tripping over the features that were prominently placed because that's what it has been optimized for.
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,345
10/7/04 9:08:18 PM
|
I'm gradually warming up to it
Right now I'm doing a lot of shell and wish I could use Perl for some things. Will wonders never cease?
-drl
|
Post #178,386
10/8/04 2:17:42 AM
|
That should be in the man page.
Or something.
Scott's comment echoes my own problem(s) with Perl and your reply is extremely astute.
Wade, who has several times made the mistake of approaching Perl incorrectly.
Is it enough to love Is it enough to breathe Somebody rip my heart out And leave me here to bleed
| | Is it enough to die Somebody save my life I'd rather be Anything but Ordinary Please
| -- "Anything but Ordinary" by Avril Lavigne. |
|
Post #178,301
10/7/04 5:36:33 PM
|
Is this a sort of typecasting?
push @{ $norm{$val} }, $key;
Specifically the @{ }
I ask because later on when trying to print out the list I end up needing to say
for my $item ( @{ $norm{$key} } ) { print $item; }
where I had to add the @{ } to get something different from <ARRAY0xCRAP> from printing and see the elements again.
I expected $norm{$key} to be a list but it seems to be more like some kind of wrapper.
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #178,311
10/7/04 6:00:50 PM
|
It's a reference
|
Post #178,312
10/7/04 6:10:14 PM
|
Sort of
What's actually happening is that $norm{$val} is the reference to the array. Decorating it by @{ $norm{$val} } accesses the array.
It's the same kind of dereferencing that you go through in C to get at a struct that you have a pointer to.
You could also write ${ $norm{$val} }[3] to access the 4'th element. Or use the syntactic shortcut $norm{$val}[3].
As for your expectation, you're tripping over the fact that Perl is a list-oriented language. There is no such thing as a straight list in Perl. Nothing will act "like a list". Instead in a lot of places things will be interpreted as lists and will do something interesting.
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,310
10/7/04 5:58:41 PM
|
Interesting....
my %norm = { "a" => (), "b" => (), "c" => () };
all of those ()s get expanded to nothing, Perl actually sees,
my %norm = { "a", "b", "c"
Just to refresh my memory, the key is that those () are effectively nothing. If he had used a reference to an empty array, that (part) would work, no? so, one solution would be @empty_array; my %norm = { "a" => \\@empty_array; "b" => \\@empty_array; "c" => \\@empty_array; }
|
Post #178,317
10/7/04 6:27:50 PM
|
The solution would have its own problems
In particular, now all values are the same, and so updating one updates them all. You were looking for this: \nmy %norm =\n (\n "a" => [],\n "b" => [],\n "c" => [],\n );\n (note that you still need to fix the () vs {} issue.) But in any case the right solution is to assume that %norm needs no initialization at all. Perl will autovivify it to be The Right Thing. In fact that's kind of the point of having all the syntax - Perl has enough clues to be able to figure out The Right Thing and do it for you. For instance you can write: \n push @{ my $norm{$key} }, $value;\n and if need be it will realize, "There is no value in %norm for $key - I need to create one and clearly it should be an anonymous array." In, say, Ruby you'd have to write two lines - one to make sure that the array was there and another to push something onto it. (Whether the syntax is worth that benefit I'll not debate. I'm trying to explain Perl, not advocate it.) Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,370
10/7/04 11:14:47 PM
|
<bow> thank you.
|
Post #178,296
10/7/04 5:20:48 PM
|
THank you for stepping on this rake
It could have been me (*shudder*)
--
... a reference to Presidente Arbusto. -- [link|http://itre.cis.upenn.edu/~myl/languagelog/archives/001417.html|Geoffrey K. Pullum]
|
Post #178,299
10/7/04 5:30:04 PM
|
He was overcomplicating it
As I said before, a complete solution in Perl looks like this: \nmy %norm;\nwhile( my($key, $val) = each %den) {\n push @{ $norm{$val} }, $key;\n}\n Nothing more is needed. He wrote a ton more code because he was lost and was trying pretty random stuff without direction. Now why not tackle the same problem in C++? We have a hash (in this case named %den) that maps keys to values. We want a reverse lookup that maps values to an array listing the keys that lead to that value. How much code does that take? Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,303
10/7/04 5:43:24 PM
|
Well, maybe
I don't have what you'd call a rich relationship with the shell - I'm more of a real programming type.
I am trying to change though.
The idea of context in perl is subtle and difficult to grasp.
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #178,313
10/7/04 6:12:17 PM
|
Agreed
Context becomes even more subtle because most people gloss over it. It does what they expect most of the time and they don't ever sit back and think, "You know, that expectation was pretty unreasonable - how the heck did Perl decide to do that?"
Personally I think that context is a design mistake. Most Perl fans disagree.
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,319
10/7/04 6:36:09 PM
|
Agree its a mistake
"Personally I think that context is a design mistake."
I'm coming to strongly dislike implicit anything in programming languages.
Implicit type conversions and object copying are the leading cause of unexpected behavior (bugs) in C++.
But we have perl everywhere here so I'd better come to grips with it.
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #178,325
10/7/04 6:45:32 PM
|
Same here.
I've come to despise implicit behavior. Implicit build options, implicit languages. Bleh. Fine when I'm by myself (sometimes), but not in a group of people who may or may not know what they're doing.
Regards,
-scott anderson
"Welcome to Rivendell, Mr. Anderson..."
|
Post #178,327
10/7/04 6:56:48 PM
|
Right
But Perl has critical mass, CPAN is wonderful, there are lots of jobs using it, I know it well and I have a reputation for knowing it well.
That's worth some warts to me.
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,350
10/7/04 10:02:43 PM
|
Shame about the inertia. Python's design is "least surprise"
But even *that* doesn't stop a few surprises in the first couple of days working with it. ;)
|
Post #178,359
10/7/04 10:53:12 PM
|
When I started with Perl...
Python had some major design mistakes. Like lack of lexical scoping. Most of those have now been fixed, but the result is that the language has been more in flux than Perl has. (Though Perl 6 will be an even bigger break for the Perl community.)
I've looked at Python. I see no compelling arguments for me to use it. I've known lots of people who've tried both it and Perl extensively. Many prefer it to Perl, many prefer Perl to it. That seems to be a matter of taste. I prefer to avoid arguments about taste unless there is a more important issue lurking.
The features that I value that Perl has which Python doesn't are CPAN, strict.pm, and taint checking. Python is working on its equivalent to CPAN. What strict.pm does is catch most of my typos. It is nice having a typo checker in Perl, though honestly most of the typos that it catches are slip-ups in syntax. (eg I'll write $foo{bar} when I meant $foo->{bar}.) I often don't care about taint checking, but when I do I'd really feel the lack.
I'm sure that if I used Python a lot I'd have a list of features that Python has which Perl doesn't. I suspect that it would also not be a long list, and most of the items are ones that I could survive without.
And so it remains, the only scripting language that I've encountered that I really prefer to Perl is Ruby. I don't use it because it is easier for me to be employed programming Perl. Therefore I'm always rusty. But even so, there are times (particularly when I want to play with big numbers) that I'll reach for Ruby.
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,383
10/8/04 1:53:55 AM
|
On Perl 6
Would you mind posting a one-page simpleton's summary of what's new and shiny and different in Perl 6?
I use Perl as a kind of Turbo Awk On Steroids, so I imagine that it'd have to change fairly drastically for me to notice much.
Peter [link|http://www.debian.org|Shill For Hire] [link|http://www.kuro5hin.org|There is no K5 Cabal] [link|http://guildenstern.dyndns.org|Blog]
|
Post #178,409
10/8/04 8:37:56 AM
|
Re: On Perl 6
OK, so it ain't one page. It ain't anywhere CLOSE to one page. Matter of fact, it's the closest I can find to The Whole Shebang: [link|http://dev.perl.org/perl6/apocalypse/|Larry Wall's Apocalypses].
-YendorMike
"They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety." - Benjamin Franklin, 1759 Historical Review of Pennsylvania
|
Post #178,462
10/8/04 12:54:37 PM
|
I had a nice response to this typed up
And then I visited [link|http://www.msnbc.msn.com/id/6205119/|http://www.msnbc.msn.com/id/6205119/] and Galeon locked up on me. Gah. So you're getting the really short version. Some things are just plain different. For instance method calls are . rather than ->, you write %foo{$bar} rather than $foo{$bar}, a few operators changed, etc. Most of the changes make the language less surprising for people who are learning it. Perl regular expressions now have facilities for flexibly capturing lots of information about the match. You also can build them up from small pieces. This has all been carefully designed so that you can write something that looks a lot like a BNF grammar and you'll get a regular expression that actually parses that grammar. (It is only a recursive descent parser though.) These complex regular expressions are known as (surprise, surprise) grammars. Perl 6's grammar will be a Perl 6 grammar. This grammar will be available to play with, and can be overridden on the fly (this is the upside of a recursive descent parser - you can play these games). This is expected to replace the games that (some) people play today with source filters. There are many small improvements. For instance: \n# multi-way comparisons now work\nif (1 < $x < 10) {\n ...\n}\n\n# Sometimes you don't need parens where you once did.\nif 1 < $x < 10 {\n ...\n}\n\n# I used it, but didn't point out that this is the\n# "TBD" operator. It is legal Perl but throws an\n# exception if it executes.\n...\n\n# The print here syntax has some new tricks.\n print <<EOT;\n And we write some text here using the\n "print here" syntax. Note that leading\n whitespace will be stripped to the EOT\n marker, letting us maintain code indentation\n but easily output a block of text that isn't\n indented.\n EOT\n\n# Pipelines let us write code top to bottom where\n# previously it was bottom to top. Compare a\n# Schwartzian transform in Perl 5:\nmy @shortest_first # 5\n = map { $_->[0] } # 4\n sort { $a->[1] <=> $b->[1] } # 3\n map { [ $_, $_->height ] } # 2\n @animals; # 1\n# with one in Perl 6:\n@animals # 1\n ==> map { [ $_, .height ] } # 2\n ==> sort { $^a[1] <=> $^b[1] } # 3\n ==> map { $_[0] } # 4\n ==> my @shortest_first; # 5\n\n# Junctions let you write code like this:\nif any(@these) > all(@those) {\n print "These have the largest element\\n";\n}\n Perl 6 has a much richer object system. It adds lots of goodies for those who like functional programming. Named arguments to functions. And a swarm of smaller improvements. Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,588
10/9/04 2:53:04 AM
|
Many thanks for that
It was the really short version that I wanted :-)
[Obsequious note: you're getting (noticeably, over the past 18 months or so) very good at this sort of thing - *fawn*]
Peter [link|http://www.debian.org|Shill For Hire] [link|http://www.kuro5hin.org|There is no K5 Cabal] [link|http://guildenstern.dyndns.org|Blog]
|
Post #178,458
10/8/04 12:46:50 PM
|
We're having a little brown bag on Ruby
today with Dave Thomas, author of "Programming Ruby: A Pragmatic Programmer's Guide".
I'm looking forward to learning something about it.
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #178,739
10/11/04 6:55:34 AM
|
Re: We're having a little brown bag on Ruby
We're having a little brown bag on Rubytoday with Dave Thomas, author of "Programming Ruby: A Pragmatic Programmer's Guide".
Given that the today referenced above was Oct 8, and [link|http://www.robotcoop.com/weblog/24/dave-thomas-talks-about-ruby-at-amazon|this], am I right in assuming you are part of the Amazon crowd? Cool.
So, what were your impressions of the talk?
-- -- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org] --------------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
|
Post #178,740
10/11/04 7:36:30 AM
|
Shhh! Anonymous Todd works at some other...
...outfit entirely, that he calls only "BigRiverBooks"; I haven't the *faintest idea* what could be meant by that.
[link|mailto:MyUserId@MyISP.CountryCode|Christian R. Conrad] (I live in Finland, and my e-mail in-box is at the Saunalahti company.)
Your lies are of Microsoftian Scale and boring to boot. Your 'depression' may be the closest you ever come to recognizing truth: you have no 'inferiority complex', you are inferior - and something inside you recognizes this. - [link|http://z.iwethey.org/forums/render/content/show?contentid=71575|Ashton Brown]
|
Post #178,771
10/11/04 12:55:46 PM
|
I might have been there
I was "the" guy who raised his hand when asked if anyone knew anything about WebObjects.
I thought the talk was rather good (in that Thomas is definitely a "fun" speaker) from an introduction perspective. The bogging down in what is and is not "strong typing" from "those who do not get it" was a bit of a drag. I thought Thomas handled it well by simply caving on the point and moving on.
I would have liked to see more rails examples. That's the kind of development we do so that would have been the most interesting to our crowd.
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #178,774
10/11/04 1:14:57 PM
|
Re: I might have been there
Dave certainly is ranked near the top of my list of speakers to listen to.
I would have liked to see more rails examples. That's the kind of development we do so that would have been the most interesting to our crowd.
I've done one simple Rails app (demo at [link|http://onestepback.org:3030|http://onestepback.org:3030]). It took a couple of evenings to throw together. Source code is in the CVS repository at [link|http://rubyforge.org/projects/storycards|http://rubyforge.org/projects/storycards] (however, keep in mind this was my first Rails project and I certainly did some things the hard way).
Rails is certainly getting a lot of attention right now. David Heinemeier Hansson's talk at [link|http://www.rubycentral.org/conference/|RubyConf(2004)] was one of the most anticipated talk of the conference.
-- -- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org] --------------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
|
Post #178,464
10/8/04 1:02:20 PM
|
Re: strict -- have you seen pychecker?
[link|http://pychecker.sourceforge.net|http://pychecker.sourceforge.net]
The Sig: "Despite the seemingly endless necessity for doing so, it's actually not possible to reverse-engineer intended invariants from staring at thousands of lines of code (not in C, and not in Python code either)." Tim Peters on python-dev
|
Post #178,466
10/8/04 1:08:02 PM
|
No I hadn't, thanks
In fact that looks better than strict.pm.
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,463
10/8/04 12:57:52 PM
|
BTW Arkadiy, I'm still waiting for a response
Now why not tackle the same problem in C++? We have a hash (in this case named %den) that maps keys to values. We want a reverse lookup that maps values to an array listing the keys that lead to that value.
How much code does that take?
I'd still like to see that example.
Thanks, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,486
10/8/04 3:21:37 PM
10/8/04 3:22:09 PM
|
I am not saying it's shorter in C...
Let's try...
>>>>>>>>>>>>>>>>>>>>>>>> #include <iostream> #include <map> #include <vector> #include <string>
using namespace std;
int main(int argc, char **argv) { map<string, string> den;
den["one"] = "a"; den["two"] = "b"; den["three"] = "c"; den["four"] = "b"; den["five"] = "c"; den["six"] = "a"; den["seven"] = "b";
map<string, vector<string> > norm;
for (map<string, string>::iterator i = den.begin(); i != den.end(); i++) { string key = i->first; string value = i->second;
vector<string> listOfKeys = norm[value]; listOfKeys.push_back(key); norm[value] = listOfKeys; }
for (map<string, vector<string> >::iterator i = norm.begin(); i != norm.end(); i++) { cout << i->first << endl << " "; for (vector<string>::iterator j = i->second.begin(); j != i->second.end(); j++) { cout << *j << " "; } cout << endl; } }
<<<<<<<<<<<<<<<<<<<
The relevant code is 8 lines, and attrociously ineficient to boot. I can make it more efficient by storing pointer to vector instead of vector itself, but then it will be even longer, and bug-prone since I have to discard STL's memory management.
The reason for my comment is that I would have made all the same mistakes as Todd. You can see it in my C code. And the reason for *shudder* is really superluous - the syntax of @{...} to access a value in a hash by reference. Mind you, there is no nice way to do it in STL either...
I guess Perl's ability to just do what I mean in some cases, and require really arcane syntax to do obvious things in others throws me off. I haven't developed the "Perl Sense" that would tell me when the context is right, and when it isn't. Yes, it simply means that I am not a Perl programmer. Guilty as charged.
--
... a reference to Presidente Arbusto. -- [link|http://itre.cis.upenn.edu/~myl/languagelog/archives/001417.html|Geoffrey K. Pullum]
Edited by Arkadiy
Oct. 8, 2004, 03:22:09 PM EDT
|
Post #178,487
10/8/04 3:34:09 PM
|
And now for my real comment
If someone didn't know any of the STL stuff that you used, but had some half-understood samples around to start with and flailed around for a while until giving up, what would the final result look like? What would that code do?
I don't think that Todd's attempt was particularly unreasonable given where he is in Perl. I also don't think that you should judge what Perl is like to use based on it. I furthermore submit that if you judged the language that you mostly use by how you were judging Perl (ie how badly a beginner in that language can thrash around without making progress), it would come out sucking just as badly.
No, you're not a Perl programmer. Which is fine. But until you care to learn the language, please don't throw out gratuitous insults.
Thank you, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,489
10/8/04 3:47:36 PM
|
May be it's a hindsight thing
but it seems to me that it took me less time and less effort to understand C, C++ and STL that it takes me to understand Perl. My "*shudder*" was not based on Todd's code, but rather on your code. As you say yourself, in Perl you have to be aware of the context at all times, and it's hard to stay aware because most of the time it "just works". In C++ I don't have such problem. May be because it became a second nature to me so long ago. Then again, in Smalltalk, I don't have such problem either. Probably because those languages don't try to magically do what I mean in most cases.
--
... a reference to Presidente Arbusto. -- [link|http://itre.cis.upenn.edu/~myl/languagelog/archives/001417.html|Geoffrey K. Pullum]
|
Post #178,520
10/8/04 6:13:45 PM
|
It could be many things
I know that when I learned to program in Perl, the course seemed much smoother than when I set out to learn other languages later. But then I realized that there were several factors: - I misremember how long I took to learn Perl. It feels like I picked up the book and was writing it fluently a few weeks later. But I know that there were important parts of the language that I learned a lot later.
- When I was a baby in Perl, I tried to do baby-like things with it and succeeded. Now when I look at new languages, I over-reach. I immediately try to do things that I know how to do in Perl, and don't know enough to do them.
- When I learned Perl there was a constant feeling of accomplishment because I didn't know any way to easily do what I just learned. In other languages that sense is gone because whatever I just learned, I already knew how to do.
As for context, I think that it is important to know about context, but ideally it sinks into being a reflex. It's handled by the same part of your brain that handles grammar and knows when, for instance, you have to switch from past to present to future tense. Certainly I am not conciously aware of thinking about context, though I can tell you what is going on with it at any given moment. Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,581
10/9/04 12:22:32 AM
|
I don't know - multimap
as I read through the example, I could see why he went from a hash to a hash of arrays -- perl dosn't really have a multimap facility that I know of.
As I looked at with C++ & STL; I thought, why are we putting it in an array at all?
#include <iostream> #include <map> #include <vector> #include <string> int main(int argc, char **argv) { std::map<std::string, std::string> den; den["one"] = "a"; den["two"] = "b"; den["three"] = "c"; den["four"] = "b"; den["five"] = "c"; den["six"] = "a"; den["seven"] = "b"; std::multimap<std::string , std::string> norm; for (std::map<std::string, std::string>::iterator i = den.begin(); i != den.end(); i++) { norm.insert(std::pair<std::string, std::string>(i->second, i->first)); } std::string s; std::multimap<std::string, std::string>::iterator pos; for (std::multimap<std::string, std::string >::iterator i = norm.begin(); i != norm.end(); i++) { if (s != i->first) { s = i->first; std::cout << i->first << ":"; for (pos = norm.lower_bound(i->first); pos != norm.upper_bound(i->first); ++pos) { std::cout << pos->second << " "; } std::cout << std::endl; } } std::cout << std::endl; }
I'll admit a lot of wasted effort for the formatted output. But, given the times for data lookup...
|
Post #178,606
10/9/04 12:17:47 PM
|
Re: I don't know - multimap
I thought about it, but then decided to stay true to the original format. May be Todd wanted to do something with arrays later... Your version is more efficient, too.
--
... a reference to Presidente Arbusto. -- [link|http://itre.cis.upenn.edu/~myl/languagelog/archives/001417.html|Geoffrey K. Pullum]
|
Post #178,607
10/9/04 12:25:52 PM
|
Why the worry about efficiency?
You're comparing with Perl. Pretty much anything is at least 10x faster in C than Perl. Any semi-sane C++ version will be faster. And take less memory. If programmer time is less important than those factors, then Perl is definitely the wrong language.
Furthermore standard programming advice - which I follow even in Perl - is to not micro-optimize. Concentrate on making the design clean, and if performance is a problem later (it usually isn't), then benchmark for the hotspots and optimize that. Always thinking about efficiency looks a heck of a lot like micro-optimizing to me.
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,608
10/9/04 12:30:44 PM
|
I worry about efficiency
because I deliberately picked O(n^2) that looks clean to someone who doesn't care to go into STL's intricacies. I could have gotten O(n log n). I think it's a good trade-off for a sample code, but I am used to be aware of such trade-offs. AT the level I usually program, that kind of decision is a difference between 12,000 traps per second and 4,000 traps per second.
--
... a reference to Presidente Arbusto. -- [link|http://itre.cis.upenn.edu/~myl/languagelog/archives/001417.html|Geoffrey K. Pullum]
|
Post #178,612
10/9/04 12:59:07 PM
|
Ah
Yeah, I tend to be aware of O(n) vs O(n*log(n)). If my data set is small I might go for the worse one, but might not.
One nice thing about Perl is that often the most obvious way to write something is also pretty good algorithmically. That is because you reach for hashes early, which have average performance O(1). (Worst case O(n), I've never seen that happen accidentally though...)
So the Perl solution offered is O(n) average case, with an unlikely worst case performance of O(n^2).
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,610
10/9/04 12:41:13 PM
|
C vs Perl - efficiency - untrue for me
I'm almost always bottlenecked on IO. Well, maybe not any more with the new arrays. But for my type of data munging for data warehouse work, Perl has been a fast as C when I did my simple tests.
|
Post #178,613
10/9/04 1:11:47 PM
|
Point - but you may want to rebenchmark
I know that historically on Linux, Perl's I/O performance was not up to snuff. I don't remember the exact cause, but the situation was bad enough that with a default compile it could be faster to read data and split it into lines inside of Perl rather than have Perl do that splitting!
I believe that this has since been fixed.
Another vague memory tells me that enabling Unicode processing can add significant overhead to Perl's I/O.
And, of course, the default Perl 5.8 that shipped with Red Hat 9 was compiled with threads and significantly underperformed any version of Perl that you'd be likely to compile for yourself. People benchmarking that gave rise to a myth that Perl 5.8 was a lot slower than 5.6. Nope. If you compile with the same options, the speeds are basically equivalent. But the version of 5.8 shipped by Red Hat was slower than their version of 5.6. Here are [link|http://mathforum.org/epigone/modperl/clikingspimp/1068515972.2699.131.camel@localhost.localdomain|some benchmarks] that a friend of mine did.
Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|
Post #178,521
10/8/04 6:16:21 PM
|
Here's a smalltalk version
| den norm |
den := Dictionary newFrom: { 'one'->'a'. 'two'->'b'. 'three'->'c'. 'four'->'b'. 'five'->'c'. 'six'->'a'. 'seven'->'b' }.
norm := Dictionary new. den keysAndValuesDo: [:key :val | (norm at: val ifAbsentPut: (OrderedCollection new)) add: key].
The wackiness in the perl seems to be that you cannot use a reference as the thing to which it refers. Which to me implies that reference is poorly named. C++ references are indistinguishable from the things they reference. Ditto file references in unix (symbolic links act just like the files to which they refer most of the time).
I'd be inclined to think of the perl reference as a "pointer" which requires dereferencing to actually use.
Will this thinking mess me up?
That was lovely cheese.
--Wallace, The Wrong Trousers
|
Post #178,522
10/8/04 6:43:04 PM
|
Yes, think of a reference as a pointer
My understanding of the reasoning behind the name is that a reference is supposed to keep track of what it points to and garbage collect it if needed. Perl does that. Therefore it isn't a pointer and shouldn't be called on. As for whether a reference should look like what it is pointing at, I'd call that choice consistent with Perl's design. Think C for a second. Suppose that foo is a struct and bar a pointer to foo. You can access a field baz in the struct either through foo.baz or bar->baz. Let's carry this analogy through to references and OO syntax. If you think of objects, etc as immediate, then a C-trained person would be inclined to use the . notation. Unfortunately Perl had already used . for string concatenation and so in Perl 5 they didn't want to use it for method calls etc. However for a C-trained person it makes just as much sense to say that there is a level of indirection visible everywhere, and you use -> instead. Which is exactly what Perl did. You access things through a reference using the notation that you would for a pointer in C, and this notation is used for method calls as well. The idea of this indirection goes surprisingly far. Take, for instance, the following: \nmy $bar = my $baz = bless {}, 'Package::A';\nbless $bar, 'Package::B';\nprint ref($baz); # prints Package::B\n What happened is that since an object is a blessed reference, and everything OO in Perl happens through a layer of indirection, the package an object belongs to is stored on the data that is object, not in the reference pointing to the object. So the effect of calling bless on one reference to the object is visible from every other copy of said object. Unfortunately for Perl, nobody else made that design choice. So as reasonable a choice as it may have seemed when it was made a decade ago, it causes pain and confusion now. Which is why Perl 6 (whose syntax is deliberately not backwards compatible with Perl 5) will reverse that choice. Cheers, Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
|