Sunday, February 12, 2012

Physical Constants


PhysicalConstants

The Physical Constants package pre-dates most of the curated data and, not being in the same format as the latter, is accessed differently.

In[284]:= << PhysicalConstants`

In[285]:= Names["PhysicalConstants`*"]

Out[285]= {"AccelerationDueToGravity", "AgeOfUniverse", "AvogadroConstant", \
"BohrRadius", "BoltzmannConstant", "ClassicalElectronRadius", \
"CosmicBackgroundTemperature", "DeuteronMagneticMoment", "DeuteronMass", \
"EarthMass", "EarthRadius", "ElectronCharge", "ElectronComptonWavelength", \
"ElectronGFactor", "ElectronMagneticMoment", "ElectronMass", \
"FaradayConstant", "FineStructureConstant", "GalacticUnit", \
"GravitationalConstant", "HubbleConstant", "IcePoint", "MagneticFluxQuantum", \
"MolarGasConstant", "MolarVolume", "MuonGFactor", "MuonMagneticMoment", \
"MuonMass", "NeutronComptonWavelength", "NeutronMagneticMoment", \
"NeutronMass", "PlanckConstant", "PlanckConstantReduced", "PlanckMass", \
"ProtonComptonWavelength", "ProtonMagneticMoment", "ProtonMass", \
"QuantizedHallConductance", "RydbergConstant", "SackurTetrodeConstant", \
"SolarConstant", "SolarLuminosity", "SolarRadius", \
"SolarSchwarzschildRadius", "SpeedOfLight", "SpeedOfSound", "StefanConstant", \
"ThomsonCrossSection", "VacuumPermeability", "VacuumPermittivity", \
"WeakMixingAngle"}

In[286]:= AccelerationDueToGravity

Out[286]= (196133 Meter)/(20000 Second^2)


This will generate a 3-column list of the constants and their values. Note the particular syntax of Partition, which is used to handle remnants at the end of a partitioned List. I explain this under Partition.

Table[{i, ToExpression@i}, {i, Names@"PhysicalConstants`*"}] //
  Partition[#, 3, 3, 1, {}] & // TableForm

And this will generate a list of the explanations of all constants. Note that the list is not in a form that can be manipulated, such as put into a more compact table, without some machinations of which I'm ignorant.

Information@# & /@ Names@"PhysicalConstants`*"

Finally, for this blog, here is a compact two-column table of the constants.


In[287]:= Thread[{Names["PhysicalConstants`*"],
   ToExpression /@ Names["PhysicalConstants`*"]}] // TableForm

Mathematica Table of Physical Constants


Element Data


Again we typically list the Properties available for the curated data collection.

ElementData@"Properties"

{"Abbreviation", "AbsoluteBoilingPoint", "AbsoluteMeltingPoint", \
"AdiabaticIndex", "AllotropeNames", "AllotropicMultiplicities", \
"AlternateNames", "AlternateStandardNames", "AtomicNumber", "AtomicRadius", \
"AtomicWeight", "Block", "BoilingPoint", "BrinellHardness", "BulkModulus", \
"CASNumber", "Color", "CommonCompoundNames", "CovalentRadius", \
"CriticalPressure", "CriticalTemperature", "CrustAbundance", \
"CrystalStructure", "CuriePoint", "DecayMode", "Density", \
"DiscoveryCountries", "DiscoveryYear", "ElectricalConductivity", \
"ElectricalType", "ElectronAffinity", "ElectronConfiguration", \
"ElectronConfigurationString", "Electronegativity", \
"ElectronShellConfiguration", "FusionHeat", "GasAtomicMultiplicities", \
"Group", "HalfLife", "HumanAbundance", "IconColor", "IonizationEnergies", \
"IsotopeAbundances", "KnownIsotopes", "LatticeAngles", "LatticeConstants", \
"Lifetime", "LiquidDensity", "MagneticType", "MassMagneticSusceptibility", \
"MeltingPoint", "Memberships", "MeteoriteAbundance", "MohsHardness", \
"MolarMagneticSusceptibility", "MolarVolume", "Name", "NeelPoint", \
"NeutronCrossSection", "NeutronMassAbsorption", "OceanAbundance", "Period", \
"Phase", "PoissonRatio", "QuantumNumbers", "Radioactive", "RefractiveIndex", \
"Resistivity", "ShearModulus", "SolarAbundance", "SoundSpeed", \
"SpaceGroupName", "SpaceGroupNumber", "SpecificHeat", "StableIsotopes", \
"StandardName", "SuperconductingPoint", "ThermalConductivity", \
"ThermalExpansion", "UniverseAbundance", "Valence", "VanDerWaalsRadius", \
"VaporizationHeat", "VickersHardness", "VolumeMagneticSusceptibility", \
"YoungModulus"}

There are often, but not always, annotations explaining the meaning of a given data property or class.

In[104]:= ElementData["Hydrogen", "ElectronShellConfiguration", "LongDescription"]

Out[104]= "occupation numbers for each complete energy shell"

Here is the complete table. We use a Table listing the properties we want to extract from the database and display that iterates over the atomic numbers from 1 to 118. Then we need to Flatten the List for each element so that the last field, ElectronShellConfiguration, displays the number of electrons in each shell in a row instead of a column. Compare this method to those used for AstronomicalData and PhysicalConstants.

In[283]:= Table[{ElementData[z, "AtomicNumber"], ElementData[z, "Abbreviation"],
    ElementData[z, "Name"], ElementData[z, "Series"],
    ElementData[z, "AtomicWeight"], ElementData[z, "MeltingPoint"],
    ElementData[z, "BoilingPoint"],
    ElementData[z, "ElectronShellConfiguration"]}, {z, 118}] //
  Flatten /@ # & //
 TableForm[#,
   TableHeadings -> {{}, {"Number", "Symbol", "Name", "Group",
      "Atomic Weight", "Melting Point", "Boiling Point",
      "Electron Shell\nConfiguration"}}] &


Astronomical Data


A recent extrapolation on the number of Earth-like planets is here with an exemplar here: Kepler 452b, just 1400 light years away in the constellation Cygnus. See also "The comet-like composition of a protoplanetary disk as revealed by complex cyanides."

There is a typical procedure to explore a curated data collection and extract what we need from it. For most of the curated data collections, we can find out what categories of information are available by calling the Properties field.

In[105]:= AstronomicalData@"Properties"

Out[105]= {"AbsoluteMagnitude", "AbsoluteMagnitudeH", "Albedo", "AlphanumericName", \
"AlternateNames", "AlternateStandardNames", "Altitude", "Apoapsis", \
"ApparentMagnitude", "AscendingNodeLongitude", "Azimuth", "BayerName", \
"BayerStandardName", "BlueBandMagnitude", "BVColorIndex", "Classes", \
"Constellation", "ConstellationName", "Declination", "Density", "Diameter", \
"DiscoveryYear", "Distance", "DistanceLightYears", "DurchmusterungName", \
"DurchmusterungStandardName", "EarthMOID", "Eccentricity", \
"EffectiveTemperature", "EquatorialDiameter", "EquatorialRadius", \
"EscapeVelocity", "FlamsteedName", "FlamsteedStandardName", "GalaxyType", \
"GlieseName", "GlieseStandardName", "GlobularClusterType", "Gravity", \
"HDName", "HDNumber", "HipparcosName", "HipparcosNumber", "HRName", \
"HRNumber", "HubbleType", "IAUName", "IAUNumber", "ICNumber", "Image", \
"Inclination", "LastRiseTime", "LastSetTime", "Luminosity", "Mass", \
"MeanMotion", "Name", "NextRiseTime", "NextSetTime", "NGCNumber", \
"ObjectType", "Oblateness", "Obliquity", "OrbitCenter", "OrbitPath", \
"OrbitPeriod", "OrbitPeriodYears", "OrbitRules", "Parallax", "Periapsis", \
"PeriapsisArgument", "PeriapsisLongitude", "PerihelionTime", "PGCNumber", \
"PolarDiameter", "PolarRadius", "Position", "PositionLightYears", \
"PrimaryDesignation", "PrimaryStarKSemiamplitude", "ProvisionalDesignation", \
"RadialVelocity", "Radius", "Redshift", "RightAscension", "RotationPeriod", \
"SAOName", "SAONumber", "Satellites", "SemimajorAxis", "SMASSSpectralType", \
"SpectralClass", "SpectralClassList", "Speed", "StandardName", \
"SurfaceBrightness", "TholenSpectralType", "VisualBandMagnitude"}

In[106]:= % // Length

Out[106]= 98

So there are currently 98 fields of information available for AstronomicalData. Next, note that you can list all objects in the collection by omitting any parameter.

In[107]:= {AstronomicalData[] // Short, AstronomicalData[] // Length}


You can see why I used Short--there are 156,134 astronomical objects listed in the database. In any of the collections we typically would work with a subset. There are often logical subsets built-in. In AstronomicalData they are called Classes, while in, for example, ElementData there are Classes but other categorizations there could be called classes as well.

In[121]:= AstronomicalData@"Classes"

Out[121]= {"AmorAsteroid", "ApolloAsteroid", "AtenAsteroid", "BarredSpiralGalaxy", \
"BayerObject", "BrightGiant", "BrightHIIRegion", "CarbonStar", \
"CentaurAsteroid", "ChironTypeComet", "ClassAStar", "ClassBStar", \
"ClassCStar", "ClassFStar", "ClassGStar", "ClassKStar", "ClassMStar", \
"ClassNStar", "ClassOStar", "ClassRStar", "ClassSStar", "Comet", \
"DeepSkyObject", "DwarfEllipticalGalaxy", "DwarfPlanet", \
"DwarfSpheroidalGalaxy", "EllipticalGalaxy", "EnckeTypeComet", "Exoplanet", \
"FlamsteedObject", "Galaxy", "GlieseObject", "GlobularCluster", \
"HalleyTypeComet", "HDObject", "HipparcosObject", "HRObject", \
"HyperbolicComet", "ICObject", "InnerMainBeltAsteroid", "IrregularGalaxy", \
"JupiterFamilyComet", "LocalGroup", "MainBeltAsteroid", "MainSequenceStar", \
"MarsCrossingAsteroid", "MessierObject", "MinorPlanet", "MultipleStar", \
"NakedEyeStar", "NearEarthAsteroid", "Nebula", "NGCObject", "NormalGiant", \
"OpenCluster", "OuterMainBeltAsteroid", "ParabolicComet", "PGCObject", \
"Planet", "PlanetaryMoon", "PlanetaryNebula", "Plutoid", "SAOObject", \
"SpiralGalaxy", "Star", "StarBrightest10", "StarBrightest100", \
"StarNearest10", "StarNearest100", "Subdwarf", "Subgiant", "Supergiant", \
"TransNeptunianObject", "TrojanAsteroid", "WhiteDwarfStar", "WolfRayetStar"}

In[108]:= brightest100Stars = AstronomicalData@"StarBrightest100"

Out[108]= {"Sun", "Sirius", "Canopus", "Arcturus", "RigelKentaurusA", "Vega", \
"Capella", "Rigel", "Procyon", "Achernar", "Betelgeuse", "Hadar", "Altair", \
"Acrux", "Aldebaran", "CapellaAb", "Spica", "Antares", "Pollux", "Fomalhaut", \
"Mimosa", "Deneb", "RigelKentaurusB", "Regulus", "Adhara", "Castor", \
"Gacrux", "Shaula", "Bellatrix", "Alnath", "Miaplacidus", "Alnilam", \
"Alnair", "Alnitak", "Regor", "Alioth", "Mirphak", "KausAustralis", "Dubhe", \
"Wezen", "Alkaid", "Avior", "ThetaScorpii", "Menkalinan", "Atria", "Alhena", \
"DeltaVelorum", "Peacock", "Polaris", "Mirzam", "Alphard", "Hamal", \
"Algieba", "Diphda", "Nunki", "Menkent", "Alpheratz", "Mirach", "Saiph", \
"Kochab", "BetaGruis", "Rasalhague", "Algol", "Almach", "Denebola", "Tsih", \
"GammaCentauri", "Naos", "Aspidiske", "Alphekka", "Alsuhail", "Mizar", \
"Sadr", "Shedir", "Etamin", "Mintaka", "Caph", "EpsilonCentauri", "Dschubba", \
"EpsilonScorpii", "AlphaLupi", "EtaCentauri", "Merak", "Izar", "Enif", \
"KappaScorpii", "Ankaa", "Phad", "Sabik", "Scheat", "Aludra", "Alderamin", \
"KappaVelorum", "EpsilonCygni", "Markab", "Menkar", "ZetaOphiuchi", \
"ZetaCentauri", "Zosma", "Acrab"}

I see many old friends from my early teens, when I spent cold nights with ideal still, less-stratified air gazing through a 6-inch reflector. Note, too, the plethora of Arabic names, attesting to the Muslim renaissance, which is the more significant flowstream running from the Greeks and their great predecessors to our modern culture than the story told by the typical Western-biased version of the history of science. But getting back to the matter at hand, extracting a single piece of information about a single object in the database uses the simple syntax of a descriptor for the object, such as "Sun", and a descriptor of the field, such as "AbsoluteMagnitude", both Strings.

In[130]:= AstronomicalData["Sun", "AbsoluteMagnitude"]

Out[130]= 4.84

While I can think of logical and compact syntaxes that are consistent within Mathematica to retrieve a set of objects and related fields from the database, such as AstronomicalData[{1, 100}, "ApparentMagnitude"], or AstronomicalData["StarBrightest100", "ApparentMagnitude"], we must use a less user - friendly form to extract the fields. A cumbersome syntax for this basic operation is common to all the curated databases that I know, and the syntax is also not uniform across them. Compare the following methods with the examples for ElementData and PhysicalConstants. Note again all fields are described by Strings.

In[109]:= AstronomicalData[#, "ApparentMagnitude"] & /@ brightest100Stars

Out[109]= {-26.72, -1.44, -0.62, -0.05, -0.01, 0.03, 0.08, 0.18, 0.4, 0.45, 0.45, 0.61, \
0.76, 0.77, 0.87, 0.96, 0.98, 1.06, 1.16, 1.17, 1.25, 1.25, 1.35, 1.36, 1.5, \
1.58, 1.59, 1.62, 1.64, 1.65, 1.67, 1.69, 1.73, 1.74, 1.75, 1.76, 1.79, 1.79, \
1.81, 1.83, 1.85, 1.86, 1.86, 1.9, 1.91, 1.93, 1.93, 1.94, 1.97, 1.98, 1.99, \
2.01, 2.01, 2.04, 2.05, 2.06, 2.07, 2.07, 2.07, 2.07, 2.07, 2.07, 2.09, 2.1, \
2.14, 2.15, 2.2, 2.21, 2.21, 2.22, 2.23, 2.23, 2.23, 2.24, 2.24, 2.25, 2.28, \
2.29, 2.29, 2.29, 2.3, 2.33, 2.34, 2.35, 2.38, 2.39, 2.4, 2.40, 2.43, 2.44, \
2.45, 2.45, 2.47, 2.48, 2.49, 2.54, 2.54, 2.55, 2.57, 2.56}

An alternate method to using Map is to use Table, and if we want to compile information or display a set of fields, that is how we would do it. Note the very nifty ability of Table to iterate over an arbitrary symbolic List, in this case the List of 100 brightest stars, and not just a numerical iterator.

In[118]:= Table[AstronomicalData[i, "DistanceLightYears"], {i, brightest100Stars}]

Out[118]= {0.0000158, 8.60, 3.1*10^2, 36.7, 4.39, 25.3, 42.2, 8.7*10^2, 11.4, 1.4*10^2,
 6.4*10^2, 398., 16.8, 3.*10^2, 65.1, 42.2, 2.5*10^2, 6.1*10^2, 33.7, 25.1,
 2.9*10^2, 1.55*10^3, 4.39, 77.5, 404., 51.5, 87.9, 701., 243., 131., 111.,
 1.34*10^3, 101., 7.8*10^2, 1.14*10^3, 80.9, 592., 145., 124.,
 1.79*10^3, 101., 632., 272., 82.1, 415., 105., 79.7, 183., 431., 499., 177., \
65.9, 126., 95.8, 224., 60.9, 97.0, 199., 723., 127., 170., 46.7, 92.8, 355., \
36.2, 613., 130., 1.09*10^3, 692., 74.7, 573., 77.9, 1.52*10^3, 228., 148.,
 7.2*10^2, 54.4, 376., 401., 65.4, 548., 308., 79.4, 209., 672., 464., 77.4, \
83.5, 83.9, 199.,
 3.20*10^3, 48.8, 537., 72.0, 139., 220., 365., 384., 57.7, 530.}

One of the most interesting discoveries of this epoch is the disclosure of planets surrounding stars. This discovery drastically affects the Drake equation, simple enough but elegant and pointed in conception, which calculates the number of planets bearing life and intelligent life. As Paul Horowitz pointed out years ago, if we assume the speed of light as a limiting factor governing the coincidence of an intelligent species' communication, and then consider the duration from the inception of a species' technical ability to communicate across space (e.g. radio) to their loss of desire to communicate due to the singularity of accelerated artificial intelligence (machine or genetic), there may not be many interactions between intelligent species. As of the last few months, however, extrapolating from current data, the number of planets that are capable of bearing life may be orders of magnitude greater than estimated until now. However it seems unlikely that the span from inception of interstellar communication, even inadvertent such as Marconi's invention of radio, to the advent of AI, is any different from what we currently envision, perhaps 300 years, a narrow window.

In[132]:= AstronomicalData@"Planet"

Out[132]= {"Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", \
"Neptune"}

No extra-solar planets ("exoplanets") here. Hmm, for that matter, how is Pluto categorized? Mathematica does have some syntactical elegance built-in for searching the list of all objects, but to search a class, we need Cases.

In[162]:= AstronomicalData@"*Plu*"

Out[162]= {"Pluto", "Plutarchos", "Plucker", "Pluis"}

In[143]:= AstronomicalData@"TransNeptunianObject" // Cases[#, "Pluto"] &

Out[143]= {"Pluto"}

It appears Mathematica has a separate class of extra - solar planet ("exoplanet"), a little out of date, judging by the number.

In[151]:= AstronomicalData@"Exoplanet" // Length

Out[151]= 209

So let's put together a table of information about the nearest stars and include properties that may relate to their likelihood of hosting a life-supporting planet.

In[122]:= ourNeighbors = AstronomicalData["StarNearest100"]

Out[122]= {"Sun", "ProximaCentauri", "RigelKentaurusA", "RigelKentaurusB", \
"BarnardsStar", "Wolf359", "Lalande21185", "Luyten726-8A", "Luyten726-8B", \
"Sirius", "SiriusB", "HIP92403", "Gl905", "EpsilonEridani", "Lacaille9352", \
"HIP57548", "Gl866A", "HIP104214", "Procyon", "Gl280B", "HIP104217", \
"HIP91772", "HIP91768", "HIP1475", "Gl15B", "GJ1111", "EpsilonIndi", \
"TauCeti", "HIP5643", "LuytensStar", "KapteynsStar", "Lacaille8760", \
"Kruger60", "Gl860B", "HIP30920", "Gl234B", "HIP72511", "HIP80824", "GJ1061", \
"Gl473A", "Gl473B", "HIP439", "HIP15689", "VanMaanensStar", "NN3522", \
"Gl83.1", "NN3618", "HIP72509", "NN3622", "HIP86162", "HIP85523", \
"HIP114110", "HIP57367", "GJ1002", "HIP113020", "GJ1245A", "GJ1245B", \
"HIP54211", "Gl412B", "Groombridge1618", "Gl388", "HIP82725", "HIP85605", \
"HIP106440", "HIP86214", "Omicron2Eridani", "Gl166B", "Gl166C", "HIP112460", \
"HIP88601", "Gl702B", "Altair", "HIP1242", "GJ1116A", "GJ1116B", "NN3379", \
"HIP57544", "HIP67155", "HIP103039", "HIP21088", "Gl169.1B", "HIP33226", \
"HIP53020", "HIP25878", "Gl754", "HIP82817", "Gl644B", "Gl644C", "Alsaphi", \
"HIP29295", "HIP26857", "HIP86990", "HIP94761", "Gl752B", "Gl300", \
"HIP73184", "HIP37766", "HIP76074", "Achird", "Gl34B"}

In[124]:= Table[AstronomicalData[i, "DistanceLightYears"], {i, ourNeighbors}]

Out[124]= {0.0000158, 4.22, 4.39, 4.39, 5.94, 7.79, 8.31, 8.56, 8.56, 8.60, 8.60, 9.69, \
10.3, 10.5, 10.7, 10.9, 11.1, 11.4, 11.4, 11.4, 11.4, 11.5, 11.6, 11.6, 11.6, \
11.8, 11.8, 11.9, 12.1, 12.4, 12.8, 12.9, 13.1, 13.1, 13.4, 13.4, 13.9, 13.9, \
14.0, 14.0, 14.0, 14.2, 14.3, 14.4, 14.6, 14.6, 14.6, 14.7, 14.8, 14.8, 14.8, \
15.1, 15.1, 15.3, 15.3, 15.4, 15.4, 15.8, 15.8, 15.9, 16.0, 16.1, 16.1, 16.1, \
16.4, 16.4, 16.4, 16.4, 16.4, 16.6, 16.6, 16.8, 17.0, 17.0, 17.0, 17.5, 17.6, \
17.7, 17.9, 18.0, 18.0, 18.0, 18.4, 18.6, 18.6, 18.7, 18.7, 18.7, 18.8, 18.8, \
18.9, 18.9, 19.1, 19.1, 19.2, 19.3, 19.3, 19.3, 19.4, 19.4}

To extract more fields, we use Table to iterate over the class of objects ourNeighbors and within it, Map (/@) the template for extracting a single field over a List of fields. We show just the first two to note that this method uses Transpose to group the properties of each object together. Again, compare to the method used with ElementData. Here are the apparent magnitude and absolute magnitude of the Sun and Sirius first grouped by property then with Transpose by object.

Table[AstronomicalData[i, #], {i,
    ourNeighbors[[1 ;; 2]]}] & /@ {"ApparentMagnitude", "AbsoluteMagnitude"}

Out[145]= {{-26.72, 11.01}, {4.84, 15.4}}


And here is the entire Table. I built it using the first three records so I could see what was going on as I added fields and functionality. Note that all these stars are less than 20 light years from us.

In[149]:= Sort[{{b, c}, {a, d}, {z, a}}]

Out[149]= {{a, d}, {b, c}, {z, a}}

In[282]:= Table[AstronomicalData[i, #], {i, ourNeighbors}] & /@ {"Name",
     "DistanceLightYears", "SpectralClass", "Constellation",
     "ApparentMagnitude", "AbsoluteMagnitude", "NakedEyeStar",
     "RightAscension", "Declination", "Diameter"} // Transpose //
  Sort[#, #[[2]] < #2[[2]] &] & //
 TableForm[#,
   TableHeadings -> {{}, {"Name", "Distance in\nLightYears",
      "Spectral\nClass", "Constellation", "Apparent\nMagnitude",
      "Absolute\nMagnitude", "NakedEye\nStar", "Right\nAscension",
      "Declination", "Diameter"}}] &And here is the entire Table. I built it using the first three records so I could see what was going on as I added fields and functionality. Note that all these stars are less than 20 light years from us.



Curated Data


On March 11, 1985, at a talk given at Harvard University, I heard Stephen Wolfram say that he intended what was then his precursor to Mathematica, SMP (Symbolic Manipulation Program), to contain the core of mathematical knowledge, and a library of additional files, 400 at that time, to greatly extend SMP's mathematical knowledge. Some years later, I heard him muse about how big a project it would be to include a core of scientific knowledge in Mathematica. WRI's curated data collection is the growing realization of that vision.

The curated data is extensive and there is a typical procedure to explore most of the collections. Here are several examples.

Sort, SortBy, Ordering, OrderedQ


This small family of functions is essential to programming in Mathematica. Indeed, sorting has been central to computer programming and algorithm analysis since programming's inception in the late 1950s.

See posts for:

Sort, SortBy, Ordering, OrderedQ

OrderingQ


OrderingQ

OrderingQ is the predicate of the family, which by default returns True of False if a List (or List of arguments of any function) is in "canonical" order, defined as lowest numerical or symbolic value to highest.

In[269]:= numericalList = Range@12 // RandomSample[#, 12] &

Out[269]= {11, 2, 5, 9, 1, 3, 8, 7, 4, 12, 10, 6}

In[270]:= OrderedQ@numericalList

Out[270]= False

Sort by default sorts from low to high.

In[271]:= Sort@numericalList

Out[271]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}

In[272]:= OrderedQ@%

Out[272]= True

In[273]:= alphaList = CharacterRange["a", "z"] // RandomSample[#, 12] &

Out[273]= {"l", "d", "f", "x", "o", "z", "i", "y", "w", "s", "m", "g"}

In[274]:= OrderedQ@alphaList

Out[274]= False

Again, Sort by default sorts from low to high, technically using the ASCII code for the characters.

In[275]:= Sort@alphaList

Out[275]= {"d", "f", "g", "i", "l", "m", "o", "s", "w", "x", "y", "z"}

In[276]:= OrderedQ@%

Out[276]= True

In[277]:= ToCharacterCode@alphaList

Out[277]= {{108}, {100}, {102}, {120}, {111}, {122}, {105}, {121}, {119}, {115}, {109}, \
{103}}

In[278]:= Sort@%

Out[278]= {{100}, {102}, {103}, {105}, {108}, {109}, {111}, {115}, {119}, {120}, {121}, \
{122}}

We can give OrderedQ our own ordering function, as complex as we like, to decide if the List is ordered. In this example we simply override OrderedQ's default, which is normally in accord with Sort's of ordering from small to large, and ask OrderedQ if the List is ordered from large to small.

In[281]:= OrderedQ[Sort@numericalList, Greater]

Out[281]= False

[b]

Ordering


Ordering reads out the order of the elements of a List if they were sorted. So in the Table below, the first row is the list itself, the second row shows the list sorted, and the third row shows the Ordering of the list: the eighth element (1) would be first, the third element (2) would be second, the fifth element (3) would be third, the 4th element would be last, etc. Incidentally I use SeedRandom here so that if you evaluate the code you will get the same random sample as I got.

In[208]:= SeedRandom@135; aList = RandomSample[Range@10, 10]

Out[208]= {7, 5, 2, 10, 3, 6, 4, 1, 9, 8}

In[209]:= {aList, Sort@aList, Ordering@aList} //
 TableForm[#, TableHeadings -> {{"aList", "Sort", "Ordering"}, {}}] &





What are the Positions of the largest two elements in aList? Use this syntax:

In[210]:= Ordering[aList, {-2, -1}]

Out[210]= {9, 4}

SortBy


Let's say we want to Sort a List as if a function were applied to the List but return the original elements of the List. That is what distinguishes SortBy from Sort. For example, say you want to sort 10 rolls of a die 3 times by the number of 6s that come up.

In[265]:= rollADie = Table[RandomChoice[Range@6, 3], {10}]

Out[265]= {{3, 5, 4}, {2, 1, 5}, {6, 3, 4}, {6, 6, 6}, {5, 2, 2}, {1, 3, 1}, {5, 4,
  4}, {2, 4, 1}, {2, 2, 3}, {4, 1, 4}}

In[266]:= SortBy[rollADie, Count[#, 6] &] // Reverse

Out[266]= {{6, 6, 6}, {6, 3, 4}, {5, 4, 4}, {5, 2, 2}, {4, 1, 4}, {3, 5, 4}, {2, 4,
  1}, {2, 2, 3}, {2, 1, 5}, {1, 3, 1}}

A way to think about SortBy is to consider that it can only "see" the result of applying the function to the list elements and Sorts by that result. For instance, we can write more compact expressions for sorting by one List position than with Sort. Here SortBy only sees the 2nd element of each List and Sorts by it (in ascending order since that is Sort's default).

In[267]:= SortBy[rollADie, #[[2]] &]

Out[267]= {{2, 1, 5}, {4, 1, 4}, {2, 2, 3}, {5, 2, 2}, {1, 3, 1}, {6, 3, 4}, {2, 4,
  1}, {5, 4, 4}, {3, 5, 4}, {6, 6, 6}}

SortBy can take more than one sorting function and applies them in order to break ties. In this sense SortBy can be used like successive sorts in a database or program like Microsoft Excel used as a database.

In[268]:= SortBy[rollADie, {#[[2]] &, Last}]

Out[268]= {{4, 1, 4}, {2, 1, 5}, {5, 2, 2}, {2, 2, 3}, {1, 3, 1}, {6, 3, 4}, {2, 4,
  1}, {5, 4, 4}, {3, 5, 4}, {6, 6, 6}}

 SortBy[e,f] is equivalent to Sort[{f[#],#}&/@e][[All,-1]].

Last, the Doc Center unveils the function underlying SortBy: SortBy[e,f]is equivalent to Sort[{f[#],#}&/@e][[All,-1]]. Translated into English, this says "make a List of the function f applied to each argument and that argument, then Sort by the first element of the List (i.e. the function applied to the argument), then only return the 2nd element of each List (i.e., the original List elements, but now re-ordered by the Sort.

Sort


Sort is simple in concept: It sorts a List according to a function that dictates the ordering. The default ordering function is smaller to larger (the function Less).

In[216]:= SeedRandom@345; aList1 = RandomInteger[100, 10]

Out[216]= {84, 52, 80, 41, 53, 24, 22, 0, 47, 42}

In[218]:= {Sort@aList1, Sort[aList1, Less]} // TableForm





We can specify the ordering function that Sort uses.

In[219]:= Sort[aList1, Greater]

Out[219]= {84, 80, 53, 52, 47, 42, 41, 24, 22, 0}

The ordering function always takes two arguments and compares them. Here we Sort by the second element of each sublist.

In[222]:= Sort[{{a, 2, 85}, {c, 1, 0.61}, {d, 3, 5^5}}, #[[2]] < #2[[2]] &]

Out[222]= {{c, 1, 0.61}, {a, 2, 85}, {d, 3, 3125}}

Whatever the algorithmic magic used by Sort to do its job efficiently, note that Slot1 picks out the first element to compare to the second element, which is picked out by Slot2. Here I show a Slot3 as well.

{#1[[2]], #2[[2]], #3[[2]]} & @@ {{a, 2}, {c, 1}, {d, 3}}

{2, 1, 3}

So under the hood Sort must start by doing something like applying the ordering function as a predicate, but then in architecture using the latest, greatest sorting algorithm from the computational complexity literature.

#1[[2]] < #2[[2]] &[{a, 2}, {c, 1}]

False

As holds throughout Mathematica, Sort works on symbolic arguments. If the symbols had been assigned values, of course those values would be used.

In[228]:= Clear[d, b, c, a]; Sort@{d, b, c, a}

Out[228]= {a, b, c, d}

In[229]:= a = 7; b = 2;

Sort@{d, b, c, a}

Out[230]= {2, 7, c, d}

Thursday, February 9, 2012

Numbering Things with MapIndexed

Sometimes you just want to number a List or Parts of an Expression. For example, I often want to number things that I'm putting into TableForm. Here's a simple idiom using MapIndexed. MapIndexed puts the indices as the second Part of each Expression, which the Reverse clause reverses so the number appear as the first column in TableForm.


MapIndexed[List, $Path] // Reverse /@ # & // TableForm