Cell array of strings not fully sorted? - string

I have the following Matlab function I'm working on:
function [data] = ReadAndCountWords(fileName)
fid = fopen(fileName);
data = textscan(fid, '%s');
data = sort(data{1});
for i = 1:length(data)
str = data{i};
str = lower(str(isstrprop(str, 'alpha')));
disp(str);
end
fclose(fid);
end
Right now I am passing in a text document containing The Gettysburg Address, and I want to print out the words contained in that file in order of how many times the word occurs. To get the word count I figured I would sort the cell array and then do a string comparison within my loop since it seemed simple enough. So I tried sorting my cell array with both sortrows() and sort(), but the results are the same:
but
four
god
it
it
it
now
the
the
we
we
a
a
a
a
a
a
a
above
add
advanced
ago
all
altogether
and
and
and
and
and
and
any
are
are
are
as
battlefield
be
be
before
birth
brave
brought
but
by
can
can
cannot
cannot
cannot
cause
civil
come
conceived
conceived
consecrate
consecrated
continent
created
dead
dead
dead
dedicate
dedicate
dedicated
dedicated
dedicated
dedicated
detract
devotion
devotion
did
died
do
earth
endure
engaged
equal
far
far
fathers
field
final
fitting
for
for
for
for
for
forget
forth
fought
freedom
from
from
full
gave
gave
government
great
great
great
ground
hallow
have
have
have
have
have
here
here
here
here
here
here
here
here
highly
honored
in
in
in
in
increased
is
is
is
it
it
larger
last
liberty
little
live
lives
living
living
long
long
measure
men
men
met
might
nation
nation
nation
nation
nation
never
new
new
nobly
nor
not
not
note
of
of
of
of
of
on
on
or
or
our
our
people
people
people
perish
place
poor
portion
power
proper
proposition
rather
rather
remaining
remember
resolve
resting
say
score
sense
seven
shall
shall
shall
should
so
so
so
struggled
take
task
testing
that
that
that
that
that
that
that
that
that
that
that
that
that
the
the
the
the
the
the
the
the
the
their
these
these
they
they
they
this
this
this
this
those
thus
to
to
to
to
to
to
to
to
under
unfinished
us
us
us
vain
war
war
we
we
we
we
we
we
we
we
what
what
whether
which
which
who
who
who
will
work
world
years
Why are those first 11 words out of order? I did some research on it and couldn't find anyone having the same problem, and the Matlab documentation seems to be doing it the same way I am. Any suggestions?

Some of the words start with uppercase letters. You call the sort before the "lower" command then display the words. If you put a breakpoint at line 4, you can inspect the sorted data:
'But,'
'Fourscore'
'God,'
'It'
'It'
'It'
'Liberty,'
'Now'
'The'
'The'
'We'
'We'
'a'
'a'
'a'
'a'
'a'
'a'
'a'
'above'
...
Which is sorted correctly based on the case of the words.

To count number of occurrences you can also use unique as follows:
data = {'and' 'And, ' 'cut' 'be.' 'dear' 'be' 'eggs' 'egg'}; %// example data
data = regexprep(lower(data), '[^a-z]', ''); %// make lower and remove special chars
[words, ~, labels] = unique(data);
count = histc(labels, 1:max(labels));
Result:
words =
'and' 'be' 'cut' 'dear' 'egg' 'eggs'
count =
2 2 1 1 1 1

You're converting the strings to lower-case after you sort them. Those 11 words are the ones capitalized in the original text, thus they come at the front of the list.

Related

Basic string slicing from indices

I will state the obvious that I am a beginner. I should also mention that I have been coding in Zybooks, which affects things. My textbook hasn't helped me much
I tried sub_lyric= rhyme_lyric[ : ]
Zybooks should be able to input an index number can get only that part of the sentence but my book doesnt explain how to do that. If it throws a [4:7] then it would output cow. Hopefully I have exolained everything well.
You need to set there:
sub_lyric = rhyme_lyric[start_index:end_index]
The string is as a sequence of characters and you can use string slicing to extract any sub-text from the main one. As you have observed:
sub_lyric = rhyme_lyric[:]
will copy the entire content of rhyme_lyric to sub_lyric.
To select only a portion of the text, specify the start_index (strings start with index 0) to end_index (not included).
sub_lyric = rhyme_lyric[4:7]
will extract characters in rhyme_lyric from position 4 (included) to position 7 (not included) so the result will be cow.
You can check more on string slicing here: Python 3 introduction

Is there anything else used instead of slicing the String?

This is one of the practice problems from Problem solving section of Hackerrank. The problem statement says
Steve has a string of lowercase characters in range ascii[‘a’..’z’]. He wants to reduce the string to its shortest length by doing a series of operations. In each operation he selects a pair of adjacent lowercase letters that match, and he deletes them.
For example : 'aaabbccc' -> 'ac' , 'abba' -> ''
I have tried solving this using slicing of strings but this gives me timeout runtime error on larger strings. Is there anything else to be used?
My code:
s = list(input())
i=1
while i<len(s):
if s[i]==s[i-1]:
s = s[:i-1]+s[i+1:]
i = i-2
i+=1
if len(s)==0:
print("Empty String")
else:
print(''.join(s))
This gives me terminated due to timeout message.
Thanks for your time :)
Interning each new immutable string can be expensive,
as it has O(N) linear cost with the length of the string.
Consider processing "aa" * int(1e6).
You will write on the order of 1e12 characters to memory
by the time you're finished.
Take a moment (well, take linear time) to
copy each character over to a mutable list element:
[c for c in giant_string]
Then you can perform dup processing by writing a tombstone
of "" to each character you wish to delete,
using just constant time.
Finally, in linear time you can scan through the survivors using "".join( ... )
One other possible solution is to use regex. The pattern ([a-z])\1 matches a duplicate lowercase letter. The implementation would involve something like this:
import re
pattern = re.compile(r'([a-z])\1')
while pattern.search(s): # While match is found
s = pattern.sub('', s) # Remove all matches from "s"
I'm not an expert at efficiency, but this seems to write fewer strings to memory than your solution. For the case of "aa" * int(1e6) that J_H mentioned, it will only write one, thanks to pattern.sub replacing all occurances at once.

Minimum Character that needed to be deleted

Original Problem:
A word was K-good if for every two letters in the word, if the first appears x times and the second appears y times, then |x - y| ≤ K.
Given some word w, how many letters does he have to remove to make it K-good?
Problem Link.
I have solved the above problem and i not asking solution for the above
problem
I just misread the statement for first time and just thought how can we solve this problem in linear line time , which just give rise to a new problem
Modification Problem
A word was K-good if for every two consecutive letters in the word, if the first appears x times and the second appears y times, then |x - y| ≤ K.
Given some word w, how many letters does he have to remove to make it K-good?
Is this problem is solvable in linear time , i thought about it but could not find any valid solution.
Solution
My Approach: I could not approach my crush but her is my approach to this problem , try everything( from movie Zooptopia)
i.e.
for i range(0,1<<n): // n length of string
for j in range(0,n):
if(i&(1<<j) is not zero): delete the character
Now check if String is K good
For N in Range 10^5. Time Complexity: Time does not exist in that dimension.
Is there any linear solution to this problem , simple and sweet like people of stackoverflow.
For Ex:
String S = AABCBBCB and K=1
If we delete 'B' at index 5 so String S = AABCBCB which is good string
F[A]-F[A]=0
F[B]-F[A]=1
F[C]-F[B]=1
and so on
I guess this is a simple example there can me more complex example as deleting an I element makens (I-1) and (I+1) as consecutive
Is there any linear solution to this problem?
Consider the word DDDAAABBDC. This word is 3-good, becauseDandCare consecutive and card(D)-card(C)=3, and removing the lastDmakes it 1-good by makingDandCnon-consecutive.
Inversely if I consider DABABABBDC which is 2-good, removing the lastDmakes CandBconsecutive and increases the K-value of the word to 3.
This means that in the modified problem, the K-value of a word is determined by both the cardinals of each letter and the cardinals of each couple of consecutive letters.
By removing a letter, I reduce its cardinal of the letter as well as the cardinals of the pairs to which it belongs, but I also increase the cardinal of other pair (potentially creating new ones).
It is also important to notice that if in the original problem, all letters are equivalent (I can remove any indifferently), while it is no longer the case in the modified problem.
As a conclusion, I think we can safely assume that the "consecutive letters" constrain makes the problem not solvable in linear time for any alphabet/word.
Instead of finding the linear time solution, which i think doesn't exist (among others because there seem to be a multitude of alternative solutions to each K request), i'd like to preset the totally geeky solution.
Namely, take the parallel array processing language Dyalog APL and create these two tiny dynamic functions:
good←{1≥⍴⍵:¯1 ⋄ b←(⌈/a←(∪⍵)⍳⍵)⍴0 ⋄ b[a]+←1 ⋄ ⌈/|2-/b[a]}
make←{⍵,(good ⍵),a,⍺,(l-⍴a←⊃b),⍴b←(⍺=good¨b/¨⊂⍵)⌿(b←↓⍉~(l⍴2)⊤0,⍳2⊥(l←⍴⍵)⍴1)/¨⊂⍵}
good tells us the K-goodness of a string. A few examples below:
// fn" means the fn executes on each of the right args
good" 'AABCBBCB' 'DDDAAABBDC' 'DDDAAABBC' 'DABABABBDC' 'DABABABBC' 'STACKOVERFLOW'
2 3 1 2 3 1
make takes as arguments
[desired K] make [any string]
and returns
- original string
- K for original string
- reduced string for desired K
- how many characters were removed to achieve deired K
- how many possible solutions there are to achieve desired K
For example:
3 make 'DABABABBDC'
┌──────────┬─┬─────────┬─┬─┬──┐
│DABABABBDC│2│DABABABBC│3│1│46│
└──────────┴─┴─────────┴─┴─┴──┘
A little longer string:
1 make 'ABCACDAAFABBC'
┌─────────────┬─┬────────┬─┬─┬────┐
│ABCACDAAFABBC│4│ABCACDFB│1│5│3031│
└─────────────┴─┴────────┴─┴─┴────┘
It is possible to both increase and decrease the K-goodness.
Unfortunately, this is brute force. We generate the 2-base of all integers between 2^[lenght of string] and 1, for example:
0 1 0 1 1
Then we test the goodness of the substring, for example of:
0 1 0 1 1 / 'STACK' // Substring is now 'TCK'
We pick only those results (substrings) that match the desired K-good. Finally, out of the multitude of possible results, we pick the first one, which is the one with most characters left.
At least this was fun to code :-).

String matching without using builtin functions

I want to search for a query (a string) in a subject (another string).
The query may appear in whole or in parts, but will not be rearranged. For instance, if the query is 'da', and the subject is 'dura', it is still a match.
I am not allowed to use string functions like strfind or find.
The constraints make this actually quite straightforward with a single loop. Imagine you have two indices initially pointing at the first character of both strings, now compare them - if they don't match, increment the subject index and try again. If they do, increment both. If you've reached the end of the query at that point, you've found it. The actual implementation should be simple enough, and I don't want to do all the work for you ;)
If this is homework, I suggest you look at the explanation which precedes the code and then try for yourself, before looking at the actual code.
The code below looks for all occurrences of chars of the query string within the subject string (variables m; and related ii, jj). It then tests all possible orders of those occurrences (variable test). An order is "acceptable" if it contains all desired chars (cond1) in increasing positions (cond2). The result (variable result) is affirmative if there is at least one acceptable order.
subject = 'this is a test string';
query = 'ten';
m = bsxfun(#eq, subject.', query);
%'// m: test if each char of query equals each char of subject
[ii jj] = find(m);
jj = jj.'; %'// ii: which char of query is found within subject...
ii = ii.'; %'// jj: ... and at which position
test = nchoosek(1:numel(jj),numel(query)).'; %'// test all possible orders
cond1 = all(jj(test) == repmat((1:numel(query)).',1,size(test,2)));
%'// cond1: for each order, are all chars of query found in subject?
cond2 = all(diff(ii(test))>0);
%// cond2: for each order, are the found chars in increasing positions?
result = any(cond1 & cond2); %// final result: 1 or 0
The code could be improved by using a better approach as regards to test, i.e. not testing all possible orders given by nchoosek.
Matlab allows you to view the source of built-in functions, so you could always try reading the code to see how the Matlab developers did it (although it will probably be very complex). (thanks Luis for the correction)
Finding a string in another string is a basic computer science problem. You can read up on it in any number of resources, such as Wikipedia.
Your requirement of non-rearranging partial matches recalls the bioinformatics problem of mapping splice variants to a genomic sequence.
You may solve your problem by using a sequence alignment algorithm such as Smith-Waterman, modified to work with all English characters and not just DNA bases.
Is this question actually from bioinformatics? If so, you should tag it as such.

How can I remove repeated characters in a string with R?

I would like to implement a function with R that removes repeated characters in a string. For instance, say my function is named removeRS, so it is supposed to work this way:
removeRS('Buenaaaaaaaaa Suerrrrte')
Buena Suerte
removeRS('Hoy estoy tristeeeeeee')
Hoy estoy triste
My function is going to be used with strings written in spanish, so it is not that common (or at least correct) to find words that have more than three successive vowels. No bother about the possible sentiment behind them. Nonetheless, there are words that can have two successive consonants (especially ll and rr), but we could skip this from our function.
So, to sum up, this function should replace the letters that appear at least three times in a row with just that letter. In one of the examples above, aaaaaaaaa is replaced with a.
Could you give me any hints to carry out this task with R?
I did not think very carefully on this, but this is my quick solution using references in regular expressions:
gsub('([[:alpha:]])\\1+', '\\1', 'Buenaaaaaaaaa Suerrrrte')
# [1] "Buena Suerte"
() captures a letter first, \\1 refers to that letter, + means to match it once or more; put all these pieces together, we can match a letter two or more times.
To include other characters besides alphanumerics, replace [[:alpha:]] with a regex matching whatever you wish to include.
I think you should pay attention to the ambiguities in your problem description. This is a first stab, but it clearly does not work with "Good Luck" in the manner you desire:
removeRS <- function(str) paste(rle(strsplit(str, "")[[1]])$values, collapse="")
removeRS('Buenaaaaaaaaa Suerrrrte')
#[1] "Buena Suerte"
Since you want to replace letters that appear AT LEAST 3 times, here is my solution:
gsub("([[:alpha:]])\\1{2,}", "\\1", "Buennaaaa Suerrrtee")
#[1] "Buenna Suertee"
As you can see the 4 "a" have been reduced to only 1 a, the 3 r have been reduced to 1 r but the 2 n and the 2 e have not been changed.
As suggested above you can replace the [[:alpha:]] by any combination of [a-zA-KM-Z] or similar, and even use the "or" operator | inside the squre brackets [y|Q] if you want your code to affect only repetitions of y and Q.
gsub("([a|e])\\1{2,}", "\\1", "Buennaaaa Suerrrtee")
# [1] "Buenna Suerrrtee"
# triple r are not affected and there are no triple e.

Resources