Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have a list which consists of numbers which use comma (,) instead of dot (.) as their decimal point. I would like to replace the commas, but only those commas which are followed by more than five digits, with a dot.

A little example:

{0, "", 0, 1, 3, 93345, 27, 763212, 3}

should be converted into:

{0, "", 0, 1, 3.93345`, 27.763212`, 3}
share|improve this question
    
In the first list there is no information which komma is real NumberPoint and which only komma. So You have to a) deal with the komma while or before importing this list or b) specify somehow which positions consist of FractionalParts for example. Then We can talk about details. –  Kuba Apr 25 '13 at 5:58
4  
Are you importing data into Mathematica? It might be better to just tweak the options of Import[] so that commas are interpreted as decimal points... –  J. M. Apr 25 '13 at 6:06
2  
Can you improve your question title? It's not very specific at the moment. –  Ajasja Apr 25 '13 at 12:37
    
Frink, I noticed that you have an "Unregistered" account with more reputation than this one. I have submitted a merge request on your behalf; you should have the combined "reputation" from both accounts soon. –  Mr.Wizard Aug 6 '13 at 21:58
    
You are right Mr. Wizard. Thank you for merging :-) –  RMMA Aug 8 '13 at 10:25

3 Answers 3

As already stated by others this is almost certainly an import problem and should be addressed at that level. For example:

ImportString["12,345 678,910", "Table", "NumberPoint" -> ","]
{{12.345, 678.91}}

See "Table" format documentation for more information.

Nevertheless the proposed replacement problem itself is mildly interesting.

Here is one method:

{0, "", 0, 1, 3, 93345, 27, 763212, 3} //.
 {a___, x_Integer, y_Integer, b___} /; y > 9999 :>
  {a, x + y/10`^IntegerLength[y], b}
{0, "", 0, 1, 3.93345, 27.7632, 3}

This would be inefficient for long lists because ReplaceRepeated (short from //.) will rescan the entire expression after each individual replacement. A better approach might be to something like this, the difference being that the replacement is only applied to the parts that haven't already matched:

f = # /. {a___, x_Integer, y_Integer, b___} /; y > 9999 :>
  {a, x + y/10`^IntegerLength[y], f@{b}} &;

f @ {0, "", 0, 1, 3, 93345, 27, 763212, 3} // Flatten
{0, "", 0, 1, 3.93345, 27.7632, 3}

Another approach for better efficiency would be to section the list with Partition and apply the replacement to those section, then merge with Flatten. A partition length of three is needed to avoid separating the parts of any number.

Replace[
  Partition[{0, "", 0, 1, 3, 93345, 27, 763212, 3}, 3, 3],
  {a___, x_Integer, y_Integer, b___} /; y > 9999 :>
   {a, x + y/10`^IntegerLength[y], b},
  {1}
] ~Flatten~ 1
{0, "", 0, 1, 3.93345, 27.7632, 3}

In a different direction you could use string processing which is optimized for this kind of replacement, but other aspects of your expression can change during the conversion.

s = ToString[{0, "", 0, 1, 3, 93345, 27, 763212, 3}, InputForm]

StringReplace[s, 
  int : DigitCharacter .. ~~ ", " ~~ dec : Repeated[DigitCharacter, {5, ∞}] :>
    int ~~ "." ~~ dec
] // ToExpression
{0, "", 0, 1, 3.93345, 27.7632, 3}
share|improve this answer
    
That's very nice, Mr.W. Would list /. {a___, x_Integer, y_Integer, b___} /; y > 9999 :> {a, x + y/10^IntegerLength[y], b} be similar to your 'better approach'? –  cormullion Apr 25 '13 at 7:49
    
Since you are going for the omnibus, let´s not forget a Sow/Reap one :-) –  Yves Klett Apr 25 '13 at 7:51
    
@cormullion I don't think I understand; wouldn't that catch only the first case? Using y > 9999 however is a nice shortening of IntegerLength[y] >= 5; mind if I incorporate it? –  Mr.Wizard Apr 25 '13 at 7:53
    
@Yves I'll have to think about that. An elegant method using those does not come to mind. (Not that what I wrote is elegant, but it would be nice to present Sow/Reap elegantly.) Did you have something specific in mind? –  Mr.Wizard Apr 25 '13 at 7:54
    
@Mr.Wizard Oh, yes, I didn't spot that - fail. Go ahead! –  cormullion Apr 25 '13 at 7:55

Another variation is to use SplitBy and Partition to separate the list into sublists like so:

a = {0, "", 0, 1, 3, 93345, 27, 763212, 3};
splits = Partition[SplitBy[a, TrueQ[# > 9999] &], 2, 2, {1, 1}, {{0}}]
{{{0, "", 0, 1, 3}, {93345}}, {{27}, {763212}}, {{3}, {0}}}

Then process the sublists to get the desired result:

Flatten[Join[Most[#1], Last[#1] + #2/10.^IntegerLength[#2]] & @@@ splits]
{0, "", 0, 1, 3.93345, 27.7632, 3}

I think this should be quite efficient as it keeps the pattern matching to a minimum.

share|improve this answer

I think @J. M. is right. You should import your data in another way. Try something like:

StringSplit[StringReplace[Import["C:/Filepath/Filename.txt","List" ],"," -> "." ]]

If it does not work, it would be nice if you could give us (a part of) your file you want to import.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.